diff --git a/Makefile.target b/Makefile.target
index 29fde6e..90e2739 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -389,6 +389,19 @@ obj-xtensa-y += xtensa-semi.o
 obj-xtensa-y += core-dc232b.o
 obj-xtensa-y += core-fsf.o
 
+$(call set-vpath, $(SRC_PATH)/gl)
+vmgl-server-stub.c opengl-func.h: parse-gl-h$(EXESUF)
+	$(call quiet-command,./$<,"  GEN   $@")
+GENERATED_SOURCES += vmgl-client-stub.c vmgl-server-stub.c opengl-func.h
+
+obj-gl-$(CONFIG_POSIX) += gloffscreen-xcomposite.o
+obj-gl-$(CONFIG_WIN32) += gloffscreen-wgl.o
+obj-gl-y += vmgl-exec.o mesa_mipmap.o gloffscreen-common.o
+
+obj-$(CONFIG_GL) += $(obj-gl-y)
+$(obj-gl-y): QEMU_INCLUDES+=-I../gl
+$(obj-gl-y): opengl-func.h
+
 main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 monitor.o: hmp-commands.h qmp-commands-old.h
@@ -440,6 +453,7 @@ clean:
 ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
 endif
+	rm -f parse-gl-h$(EXESUF) $(GENERATED_SOURCES)
 
 install: all
 ifneq ($(PROGS),)
diff --git a/configure b/configure
index 68f9ee6..30e0201 100755
--- a/configure
+++ b/configure
@@ -190,6 +190,7 @@ opengl=""
 zlib="yes"
 guest_agent="yes"
 libiscsi=""
+gl=""
 
 # parse CC options first
 for opt do
@@ -798,6 +799,10 @@ for opt do
   ;;
   --disable-guest-agent) guest_agent="no"
   ;;
+  --disable-gl) gl="no"
+  ;;
+  --enable-gl) gl="yes"
+  ;;
   *) echo "ERROR: unknown option $opt"; show_help="yes"
   ;;
   esac
@@ -1084,6 +1089,8 @@ echo "  --disable-usb-redir      disable usb network redirection support"
 echo "  --enable-usb-redir       enable usb network redirection support"
 echo "  --disable-guest-agent    disable building of the QEMU Guest Agent"
 echo "  --enable-guest-agent     enable building of the QEMU Guest Agent"
+echo "  --disable-gl             disable GL passthrough support"
+echo "  --enable-gl              enable GL passthrough support"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -2598,6 +2605,36 @@ if test "$usb_redir" != "no" ; then
     fi
 fi
 
+# check if OpenGL passthrough should be included
+if test "$gl" != "no" ; then
+    if test "$mingw32" = "yes" ; then
+        gl_libs="-lopengl32 -lglu32"
+    else
+        gl_libs="-lGL -lGLU -lXcomposite -lXext -ldl"
+    fi
+    if test "$darwin" = "yes" ; then
+        gl_libs="$gl_libs -L/usr/X11/lib -lX11"
+        gl_cflags="-I/usr/X11/include"
+    fi
+
+    cat > $TMPC << EOF
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+int main(void) { GL_VERSION; return 0; }
+EOF
+    if compile_prog "$gl_cflags" "$gl_libs" ; then
+        libs_softmmu="$libs_softmmu $gl_libs"
+        QEMU_CFLAGS="$QEMU_CFLAGS $gl_cflags"
+        gl="yes"
+    else
+        if test "$gl" = "yes" ; then
+            feature_not_found "opengl"
+        fi
+        gl="no"
+    fi
+fi
+
 ##########################################
 
 ##########################################
@@ -2918,6 +2955,7 @@ echo "usb net redir     $usb_redir"
 echo "OpenGL support    $opengl"
 echo "libiscsi support  $libiscsi"
 echo "build guest agent $guest_agent"
+echo "GL passthrough    $gl"
 
 if test "$sdl_too_old" = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -3292,6 +3330,10 @@ if test "$trace_default" = "yes"; then
   echo "CONFIG_TRACE_DEFAULT=y" >> $config_host_mak
 fi
 
+if test "$gl" = "yes" ; then
+  echo "CONFIG_GL=y" >> $config_host_mak
+fi
+
 echo "TOOLS=$tools" >> $config_host_mak
 echo "ROMS=$roms" >> $config_host_mak
 echo "MAKE=$make" >> $config_host_mak
diff --git a/gl/range_alloc.h b/gl/range_alloc.h
new file mode 100644
index 0000000..837c085
--- /dev/null
+++ b/gl/range_alloc.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2007 Even Rouault
+ *
+ * Modified by Ian Molton 2010
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef GL_RANGEALLOCATOR
+#define GL_RANGEALLOCATOR
+
+typedef struct {
+    unsigned int *values;
+    int count;
+} RangeAllocator;
+
+static inline void alloc_value(RangeAllocator *range, unsigned int value)
+{
+    if (value == 0) {
+        return;
+    }
+    if (range->count >= 1) {
+        int lower = 0;
+        int upper = range->count - 1;
+
+        while (1) {
+            int mid = (lower + upper) / 2;
+
+            if (range->values[mid] > value) {
+                upper = mid;
+            } else if (range->values[mid] < value) {
+                lower = mid;
+            } else {
+                break;
+            }
+            if (upper - lower <= 1) {
+                if (value < range->values[lower]) {
+                    range->values = realloc(range->values,
+                                    (range->count + 1) * sizeof(int));
+                    memmove(&range->values[lower + 1], &range->values[lower],
+                                    (range->count - lower) * sizeof(int));
+                    range->values[lower] = value;
+                    range->count++;
+                } else if (value == range->values[lower]) {
+                } else if (value < range->values[upper]) {
+                    range->values = realloc(range->values,
+                                    (range->count + 1) * sizeof(int));
+                    memmove(&range->values[upper + 1], &range->values[upper],
+                                    (range->count - upper) * sizeof(int));
+                    range->values[upper] = value;
+                    range->count++;
+                } else if (value == range->values[upper]) {
+                } else {
+                    upper++;
+
+                    range->values = realloc(range->values,
+                                    (range->count + 1) * sizeof(int));
+                    memmove(&range->values[upper + 1], &range->values[upper],
+                                    (range->count - upper) * sizeof(int));
+                    range->values[upper] = value;
+                    range->count++;
+                }
+                break;
+            }
+        }
+    } else {
+        range->values = g_malloc(sizeof(int));
+        range->values[0] = value;
+        range->count = 1;
+    }
+}
+
+/* return first value */
+static inline unsigned int alloc_range(RangeAllocator *range, int n,
+                unsigned int *values)
+{
+    int i, j;
+
+    if (range->count == 0) {
+        range->count = n;
+        range->values = g_malloc(n * sizeof(int));
+        for (i = 0; i < n; i++) {
+            range->values[i] = i + 1;
+            if (values) {
+                values[i] = range->values[i];
+            }
+        }
+        return 1;
+    } else {
+        int last_value = 1;
+
+        for (i = 0; i < range->count; i++) {
+            if ((int) range->values[i] - (int) last_value - 1 >= n) {
+                range->values = realloc(range->values,
+                                (range->count + n) * sizeof(int));
+                memmove(&range->values[i + n], &range->values[i],
+                                (range->count - i) * sizeof(int));
+                for (j = 0; j < n; j++) {
+                    range->values[i + j] = last_value + 1 + j;
+                    if (values) {
+                        values[j] = range->values[i + j];
+                    }
+                }
+                range->count += n;
+                break;
+            } else {
+                last_value = range->values[i];
+            }
+        }
+        if (i == range->count) {
+            range->values = realloc(range->values,
+                            (range->count + n) * sizeof(int));
+            for (j = 0; j < n; j++) {
+                range->values[i + j] = last_value + 1 + j;
+                if (values) {
+                    values[j] = range->values[i + j];
+                }
+            }
+            range->count += n;
+        }
+        return last_value + 1;
+    }
+}
+
+static inline void delete_value(RangeAllocator *range, unsigned int value)
+{
+    if (value == 0) {
+        return;
+    }
+    if (range->count >= 1) {
+        int lower = 0;
+        int upper = range->count - 1;
+
+        while (1) {
+            int mid = (lower + upper) / 2;
+
+            if (range->values[mid] > value) {
+                upper = mid;
+            } else if (range->values[mid] < value) {
+                lower = mid;
+            } else {
+                lower = upper = mid;
+            }
+            if (upper - lower <= 1) {
+                if (value == range->values[lower]) {
+                    memmove(&range->values[lower], &range->values[lower + 1],
+                                    (range->count - lower - 1) * sizeof(int));
+                    range->count--;
+                } else if (value == range->values[upper]) {
+                    memmove(&range->values[upper], &range->values[upper + 1],
+                                    (range->count - upper - 1) * sizeof(int));
+                    range->count--;
+                }
+                break;
+            }
+        }
+    }
+}
+
+static inline void delete_range(RangeAllocator *range, int n,
+                const unsigned int *values)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+        delete_value(range, values[i]);
+    }
+}
+
+static inline void delete_consecutive_values(RangeAllocator *range,
+                unsigned int first, int n)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+        delete_value(range, first + i);
+    }
+}
+#endif
diff --git a/gl/vmgl-exec.c b/gl/vmgl-exec.c
new file mode 100644
index 0000000..2263a9c
--- /dev/null
+++ b/gl/vmgl-exec.c
@@ -0,0 +1,3535 @@
+/*
+ * Host-side implementation of GL/GLX API
+ *
+ * Copyright (c) 2006, 2007 Even Rouault
+ * Copyright (C) 2008-2011  Intel Corporation
+ * Authors:
+ *   Even Rouault
+ *   Andrzej Zaborowski
+ *   Gordon Williams <gordon.williams@collabora.co.uk>
+ *   Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISiNG FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysemu.h"
+
+#include "vmgl-func.h"
+#include "vmgl-process.h"
+#include "vmgl.h"
+
+#ifdef DEBUG_GL
+# ifdef _WIN32
+#  define DEBUGF(...) printf(__VA_ARGS__)
+# else
+#  define DEBUGF(...) fprintf(stderr, __VA_ARGS__)
+# endif
+#else
+# define DEBUGF(...) while (0) { printf(__VA_ARGS__); }
+#endif
+
+#if (defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)) || \
+    (!defined(HOST_WORDS_BIGENDIAN) && defined(TARGET_WORDS_BIGENDIAN))
+# define DIFFERING_ENDIANNESS
+#endif
+#ifdef TARGET_WORDS_BIGENDIAN
+# define uint32_to_cpu be32_to_cpu
+# define uint16_to_cpu be16_to_cpu
+# define cpu_to_uint32 cpu_to_be32
+# define cpu_to_uint16 cpu_to_be16
+#else
+# define uint32_to_cpu le32_to_cpu
+# define uint16_to_cpu le16_to_cpu
+# define cpu_to_uint32 cpu_to_le32
+# define cpu_to_uint16 cpu_to_le16
+#endif
+
+#define GL_GLEXT_PROTOTYPES
+#define GLX_GLXEXT_PROTOTYPES
+#include "mesa_gl.h"
+
+#include "mesa_mipmap.h"
+#include "range_alloc.h"
+#include "gloffscreen.h"
+
+typedef struct VmglGLXFBConfig {
+    int format_flags;
+} VmglGLXFBConfig;
+
+/* #defines from glx.h */
+#define GLX_VENDOR	1
+#define GLX_VERSION	2
+#define GLX_EXTENSIONS	3
+
+/* We'll say the XVisual Id is actually just an index into here.  */
+static const VmglGLXFBConfig fbconfigs[] = {
+    { GLO_FF_ALPHA | GLO_FF_BITS_32 },
+    { GLO_FF_ALPHA | GLO_FF_BITS_32 | GLO_FF_DEPTH_24 },
+    { GLO_FF_ALPHA | GLO_FF_BITS_32 | GLO_FF_DEPTH_24 | GLO_FF_STENCIL_8 },
+
+    { GLO_FF_BITS_32 },
+    { GLO_FF_BITS_32 | GLO_FF_DEPTH_24 },
+    { GLO_FF_BITS_32 | GLO_FF_DEPTH_24 | GLO_FF_STENCIL_8 },
+
+    { GLO_FF_BITS_24 },
+    { GLO_FF_BITS_24 | GLO_FF_DEPTH_24 },
+    { GLO_FF_BITS_24 | GLO_FF_DEPTH_24 | GLO_FF_STENCIL_8 },
+};
+
+#define FAKE_GL_VENDOR     "Qemu"
+#define FAKE_GL_RENDERER   "VMGL Passthrough"
+#define FAKE_GL_VERSION    "1.4"
+#define FAKE_GL_MAJOR      1
+
+#define FAKE_GLX_VENDOR         "Qemu"
+#define FAKE_GLX_VERSION_STRING "1.2"
+#define FAKE_GLX_VERSION_MAJOR  1
+#define FAKE_GLX_VERSION_MINOR  2
+
+#define glGetError() 0
+
+#define GET_EXT_PTR(type, funcname, args_decl) \
+    static int detect_##funcname; \
+    static type (*ptr_func_##funcname)args_decl; \
+    if (detect_##funcname == 0) { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type (*)args_decl) \
+            glo_getprocaddress((const char *) #funcname); \
+        assert(ptr_func_##funcname); \
+    }
+
+#define GET_EXT_PTR_NO_FAIL(type, funcname, args_decl) \
+    static int detect_##funcname; \
+    static type (*ptr_func_##funcname)args_decl; \
+    if (detect_##funcname == 0) { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type (*)args_decl) \
+            glo_getprocaddress((const char *) #funcname); \
+    }
+
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+
+static void *get_glu_ptr(const char *name)
+{
+    static void *handle = (void *) -1;
+
+    if (handle == (void *) -1) {
+#ifndef WIN32
+        handle = dlopen("libGLU.so", RTLD_LAZY);
+        if (!handle) {
+            DEBUGF("can't load libGLU.so : %s\n", dlerror());
+        }
+#else
+        handle = (void *) LoadLibrary("glu32.dll");
+        if (!handle) {
+            DEBUGF("can't load glu32.dll\n");
+        }
+#endif
+    }
+    if (handle) {
+#ifndef WIN32
+        return dlsym(handle, name);
+#else
+        return GetProcAddress(handle, name);
+#endif
+    }
+    return NULL;
+}
+
+#define GET_GLU_PTR(type, funcname, args_decl) \
+    static int detect_##funcname; \
+    static type (*ptr_func_##funcname)args_decl; \
+    if (detect_##funcname == 0) { \
+        detect_##funcname = 1; \
+        ptr_func_##funcname = (type (*)args_decl) get_glu_ptr(#funcname); \
+    }
+
+static int display_function_call;
+
+#define MAX_HANDLED_PROCESS 100
+#define MAX_FBCONFIG 10
+
+typedef struct {
+    GLbitfield mask;
+    int active_texture_idx;
+} ClientState;
+
+#define MAX_CLIENT_STATE_STACK_SIZE 16
+
+typedef void *ClientGLXDrawable;
+
+typedef struct GLState GLState;
+
+typedef struct QGloSurface {
+    GLState *glstate;
+    GloSurface *surface;
+    ClientGLXDrawable *client_drawable;
+    int ready;
+    int ref;
+    QTAILQ_ENTRY(QGloSurface) next;
+} QGloSurface;
+
+struct GLState {
+    int ref;
+    int fake_ctxt;
+    int fake_share_list;
+
+    GloContext *context; /* context (owned) */
+    QGloSurface *current_qsurface; /* current rendering surface/drawable */
+    QTAILQ_HEAD(, QGloSurface) qsurfaces; /* list of surfaces/drawables for
+                                           * this context */
+
+    void *vertexPointer;
+    void *normalPointer;
+    void *colorPointer;
+    void *secondaryColorPointer;
+    void *indexPointer;
+    void *texCoordPointer[NB_MAX_TEXTURES];
+    void *edgeFlagPointer;
+    void *vertexAttribPointer[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+    void *vertexAttribPointerNV[MY_GL_MAX_VERTEX_ATTRIBS_NV];
+    void *weightPointer;
+    void *matrixIndexPointer;
+    void *fogCoordPointer;
+    void *variantPointerEXT[MY_GL_MAX_VARIANT_POINTER_EXT];
+    void *interleavedArrays;
+    void *elementPointerATI;
+
+    int vertexPointer_size;
+    int normalPointer_size;
+    int colorPointer_size;
+    int secondaryColorPointer_size;
+    int indexPointer_size;
+    int texCoordPointer_size[NB_MAX_TEXTURES];
+    int edgeFlagPointer_size;
+    int vertexAttribPointer_size[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+    int vertexAttribPointerNV_size[MY_GL_MAX_VERTEX_ATTRIBS_NV];
+    int weightPointer_size;
+    int matrixIndexPointer_size;
+    int fogCoordPointer_size;
+    int variantPointerEXT_size[MY_GL_MAX_VARIANT_POINTER_EXT];
+    int interleavedArrays_size;
+    int elementPointerATI_size;
+
+    int vertexAttrib_count[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+    int vertexAttrib_enabled[MY_GL_MAX_VERTEX_ATTRIBS_ARB];
+
+    int selectBuffer_size;
+    void *selectBuffer_ptr;
+    int feedbackBuffer_size;
+    void *feedbackBuffer_ptr;
+
+    ClientState client_state_stack[MAX_CLIENT_STATE_STACK_SIZE];
+    int client_state_sp;
+    int active_texture_idx;
+
+    uint32_t own_tab_textures[32768]; /* GLuint */
+    uint32_t *tab_textures; /* GLuint */
+    RangeAllocator own_texture_allocator;
+    RangeAllocator *texture_allocator;
+
+    uint32_t own_tab_buffers[32768]; /* GLuint */
+    uint32_t *tab_buffers; /* GLuint */
+    RangeAllocator own_buffer_allocator;
+    RangeAllocator *buffer_allocator;
+
+    uint32_t own_tab_lists[32768]; /* GLuint */
+    uint32_t *tab_lists; /* GLuint */
+    RangeAllocator own_list_allocator;
+    RangeAllocator *list_allocator;
+
+    int *own_indices;
+    int own_indices_size;
+};
+
+typedef struct {
+    ProcessStruct p;
+
+    int next_available_context_number;
+
+    int nb_states;
+    GLState default_state;
+    GLState **glstates;
+    GLState *current_state;
+
+    int nfbconfig;
+    const VmglGLXFBConfig *fbconfigs[MAX_FBCONFIG];
+    int fbconfigs_max[MAX_FBCONFIG];
+    int nfbconfig_total;
+} ProcessState;
+
+static ProcessState processes[MAX_HANDLED_PROCESS];
+
+static char *strip_extensions(const char *avail, const char *ext[])
+{
+    char *pos, *supported;
+    const char *srcp;
+
+    pos = supported = g_malloc(strlen(avail) + 2);
+    while (*ext) {
+        srcp = avail;
+        while ((srcp = strstr(srcp, *ext))) {
+            int len = strlen(*ext);
+            if (srcp[len] != ' ' && srcp[len] != '\0') {
+                srcp += len;
+                continue;
+            }
+            strcpy(pos, *ext);
+            pos += len;
+            if (srcp[len] == ' ') {
+                *pos++ = ' ';
+            }
+            break;
+        }
+        ext++;
+    }
+    *pos = '\0';
+
+    return supported;
+}
+
+static const char *glx_ext_supported[] = {
+    "GLX_ARB_multisample",
+    0
+};
+
+static char *supported_glx_extensions(void)
+{
+    static char *supported;
+
+    if (!supported) {
+        supported = strip_extensions(glo_glxqueryextensionsstring(),
+                        glx_ext_supported);
+    }
+
+    return supported;
+}
+
+static const char *gl_ext_supported[] = {
+    /* Mandatory OpenGL 1.4 Extensions */
+    "GL_ARB_depth_texture",
+    "GL_ARB_multisample",
+    "GL_ARB_multitexture",
+    "GL_ARB_point_parameters",
+    "GL_ARB_shadow",
+    "GL_ARB_texture_border_clamp",
+    "GL_ARB_texture_compression",
+    "GL_ARB_texture_cube_map",
+    "GL_ARB_texture_env_add",
+    "GL_ARB_texture_env_combine",
+    "GL_ARB_texture_env_crossbar",
+    "GL_ARB_texture_env_dot3",
+    "GL_ARB_texture_mirrored_repeat",
+    "GL_ARB_transpose_matrix",
+    "GL_ARB_window_pos",
+    "GL_EXT_bgra",
+    "GL_EXT_blend_color",
+    "GL_EXT_blend_func_separate",
+    "GL_EXT_blend_logic_op",
+    "GL_EXT_blend_minmax",
+    "GL_EXT_blend_subtract",
+    "GL_EXT_copy_texture",
+    "GL_EXT_draw_range_elements",
+    "GL_EXT_fog_coord",
+    "GL_EXT_multi_draw_arrays",
+    "GL_EXT_packed_pixels",
+    "GL_EXT_point_parameters",
+    "GL_EXT_polygon_offset",
+    "GL_EXT_rescale_normal",
+    "GL_EXT_secondary_color",
+    "GL_EXT_separate_specular_color",
+    "GL_EXT_stencil_wrap",
+    "GL_EXT_subtexture",
+    "GL_EXT_texture",
+    "GL_EXT_texture3D",
+    "GL_EXT_texture_edge_clamp",
+    "GL_EXT_texture_env_add",
+    "GL_EXT_texture_env_combine",
+    "GL_EXT_texture_lod",
+    "GL_EXT_texture_lod_bias",
+    "GL_EXT_texture_object",
+    "GL_APPLE_packed_pixels",
+    "GL_NV_blend_square",
+    "GL_SGIS_generate_mipmap",
+    "GL_SGIS_texture_border_clamp",
+    "GL_SGIS_texture_edge_clamp",
+    "GL_SGIS_texture_lod",
+    /* Optional extensions. If you get problems try disabling the below.  */
+    "GL_EXT_compiled_vertex_array",
+    "GL_ARB_copy_buffer",
+    "GL_ARB_depth_clamp",
+    "GL_ARB_draw_buffers ",
+    "GL_ARB_draw_elements_base_vertex",
+    "GL_ARB_fragment_program",
+    "GL_ARB_fragment_program_shadow",
+    "GL_ARB_fragment_shader",
+    "GL_ARB_framebuffer_object",
+    "GL_ARB_half_float_pixel",
+    "GL_ARB_map_buffer_range",
+    "GL_ARB_occlusion_query",
+    "GL_ARB_pixel_buffer_object",
+    "GL_ARB_point_sprite",
+    "GL_ARB_provoking_vertex",
+    "GL_ARB_seamless_cube_map",
+    "GL_ARB_shader_objects",
+    "GL_ARB_shading_language_100",
+    "GL_ARB_shading_language_120",
+    "GL_ARB_sync",
+    "GL_ARB_texture_non_power_of_two",
+    "GL_ARB_texture_rectangle",
+    "GL_ARB_vertex_array_bgra",
+    "GL_ARB_vertex_array_object",
+    "GL_ARB_vertex_buffer_object",
+    "GL_ARB_vertex_program",
+    "GL_ARB_vertex_shader,"
+    "GL_EXT_abgr",
+    "GL_EXT_blend_equation_separate",
+    "GL_EXT_cull_vertex",
+    "GL_EXT_framebuffer_blit",
+    "GL_EXT_framebuffer_object",
+    "GL_EXT_gpu_program_parameters",
+    "GL_EXT_packed_depth_stencil",
+    "GL_EXT_pixel_buffer_object",
+    "GL_EXT_provoking_vertex",
+    "GL_EXT_shadow_funcs",
+    "GL_EXT_stencil_two_side",
+    "GL_EXT_texture_cube_map",
+    "GL_EXT_texture_env_dot3",
+    "GL_EXT_texture_filter_anisotropic",
+    "GL_EXT_texture_rectangle",
+    "GL_EXT_texture_sRGB",
+    "GL_EXT_texture_swizzle",
+    "GL_EXT_vertex_array",
+    "GL_EXT_vertex_array_bgra",
+    "GL_3DFX_texture_compression_FXT1",
+    "GL_APPLE_client_storage",
+    "GL_APPLE_vertex_array_object",
+    "GL_ATI_blend_equation_separate",
+    "GL_ATI_envmap_bumpmap",
+    "GL_ATI_texture_env_combine3",
+    "GL_ATI_separate_stencil",
+    "GL_IBM_multimode_draw_arrays",
+    "GL_IBM_rasterpos_clip",
+    "GL_IBM_texture_mirrored_repeat",
+    "GL_INGR_blend_func_separate",
+    "GL_MESA_pack_invert",
+    "GL_MESA_texture_signed_rgba",
+    "GL_MESA_ycbcr_texture",
+    "GL_MESA_window_pos",
+    "GL_NV_depth_clamp",
+    "GL_NV_light_max_exponent",
+    "GL_NV_packed_depth_stencil",
+    "GL_NV_texture_env_combine4",
+    "GL_NV_texture_rectangle",
+    "GL_NV_texgen_reflection",
+    "GL_NV_vertex_program",
+    "GL_NV_vertex_program1_1",
+    "GL_OES_read_format",
+    "GL_SUN_multi_draw_arrays",
+    0
+};
+
+static char *compute_gl_extensions(void)
+{
+    static char *supported;
+
+    if (!supported) {
+        supported = strip_extensions((const char *) glGetString(GL_EXTENSIONS),
+                        gl_ext_supported);
+    }
+
+    return supported;
+}
+
+static inline QGloSurface *get_qsurface_from_client_drawable(GLState *state,
+                ClientGLXDrawable client_drawable)
+{
+    QGloSurface *qsurface;
+
+    if (state->current_qsurface->client_drawable == client_drawable) {
+        return state->current_qsurface;
+    }
+
+    QTAILQ_FOREACH(qsurface, &state->qsurfaces, next) {
+        if (qsurface->client_drawable == client_drawable) {
+            return qsurface;
+        }
+    }
+
+    return NULL;
+}
+
+/* This must always be called only on surfaces belonging to
+ * the current context */
+static inline void render_surface(QGloSurface *qsurface,
+                int bpp, int stride, uint8_t *buffer)
+{
+    if (!qsurface->ready) {
+        return;
+    }
+
+    glo_surface_getcontents(qsurface->surface, stride, bpp, buffer);
+}
+
+/* This must always be called only on surfaces belonging to
+ * the current context */
+static inline int resize_surface(ProcessState *process, QGloSurface *qsurface,
+                int w, int h)
+{
+    GLState *glstate = qsurface->glstate;
+    GloSurface *old_surface = qsurface->surface;
+    GloSurface *surface;
+
+    DEBUGF("resize_start\n");
+
+    glo_surface_destroy(old_surface);
+
+    surface = glo_surface_create(w, h, glstate->context);
+    if (!surface) {
+        return 0;
+    }
+    qsurface->surface = surface;
+
+    /* Client doesn't know the surface is new - need to MakeCurrent */
+    if (process->current_state == qsurface->glstate) {
+        glo_surface_makecurrent(qsurface->surface);
+    } else {
+        DEBUGF("Error: Surface is not current! %p %p\n",
+                        process->current_state,
+                        process->current_state->current_qsurface);
+        return 0;
+    }
+
+    glstate->current_qsurface->ready = 1;
+    DEBUGF("resize_done\n");
+
+    return 1;
+}
+
+static void init_process_tab(void)
+{
+    memset(processes, 0, sizeof(processes));
+}
+
+/* Argument list are internally of a type that can hold a target pointer
+ * or a host pointer.  */
+typedef target_phys_addr_t arg_t;
+
+#define ARG_TO_CHAR(x)			(int8_t) (x)
+#define ARG_TO_UNSIGNED_CHAR(x)		(uint8_t) (x)
+#define ARG_TO_SHORT(x)			(int16_t) (x)
+#define ARG_TO_UNSIGNED_SHORT(x)	(uint16_t) (x)
+#define ARG_TO_INT(x)			(int32_t) (x)
+#define ARG_TO_UNSIGNED_INT(x)		(uint32_t) (x)
+#define ARG_TO_FLOAT(x)			(*(float *) &(x))
+#define ARG_TO_DOUBLE(x)		(*(double *) (x))
+
+#define PTR_TO_ARG(x)			((unsigned long) (x))
+
+#include "vmgl-server-stub.c"
+
+static inline ClientGLXDrawable to_drawable(arg_t arg)
+{
+#ifdef TARGET_X86_64
+    if (arg > (unsigned long) -1) {
+        DEBUGF("GLXDrawable too big for this implementation\n");
+        return NULL;
+    }
+#endif
+    return (void *) (unsigned long) arg;
+}
+
+/* Bind a qsurface to a context (GLState) */
+static void bind_qsurface(GLState *state, QGloSurface *qsurface)
+{
+    qsurface->glstate = state;
+
+    QTAILQ_INSERT_HEAD(&state->qsurfaces, qsurface, next);
+
+    state->current_qsurface = qsurface;
+}
+
+/* Make the appropriate qsurface current for a given client_drawable */
+static int set_current_qsurface(GLState *state,
+                ClientGLXDrawable client_drawable)
+{
+    QGloSurface *qsurface;
+
+    if (state->current_qsurface &&
+            state->current_qsurface->client_drawable == client_drawable) {
+        return 1;
+    }
+
+    QTAILQ_FOREACH(qsurface, &state->qsurfaces, next) {
+        if (qsurface->client_drawable == client_drawable) {
+            state->current_qsurface = qsurface;
+            return 1;
+        }
+    }
+
+    state->current_qsurface = NULL;
+
+    return 0;
+}
+
+static int get_server_texture(ProcessState *process,
+                uint32_t client_texture)
+{
+    if (client_texture < 32768) {
+        return process->current_state->tab_textures[client_texture];
+    } else {
+        DEBUGF("invalid texture name %d\n", client_texture);
+        return 0;
+    }
+}
+
+static GLuint get_server_buffer(ProcessState *process,
+                uint32_t client_buffer)
+{
+    if (client_buffer < 32768) {
+        return process->current_state->tab_buffers[client_buffer];
+    } else {
+        DEBUGF("invalid buffer name %d\n", client_buffer);
+        return 0;
+    }
+}
+
+static GLuint get_server_list(ProcessState *process, uint32_t client_list)
+{
+    if (client_list < 32768) {
+        return process->current_state->tab_lists[client_list];
+    } else {
+        DEBUGF("invalid list name %d\n", client_list);
+        return 0;
+    }
+}
+
+static const VmglGLXFBConfig *get_fbconfig(ProcessState *process,
+                uint32_t client_fbconfig)
+{
+    int i;
+    int nbtotal = 0;
+
+    for (i = 0; i < process->nfbconfig; i++) {
+        assert(client_fbconfig >= 1 + nbtotal);
+        if (client_fbconfig <= nbtotal + process->fbconfigs_max[i]) {
+            return &process->fbconfigs[i][client_fbconfig - 1 - nbtotal];
+        }
+        nbtotal += process->fbconfigs_max[i];
+    }
+    return 0;
+}
+
+static int glXChooseVisualFunc(const uint32_t *attrib_list)
+{
+    if (attrib_list == NULL) {
+        return 0;
+    }
+
+    int format_flags = glo_flags_get_from_glx(attrib_list, 1);
+    int i;
+    int best_config = 0;
+    int best_score = -1;
+
+    for (i = 0; i < ARRAY_SIZE(fbconfigs); i++) {
+        int score = glo_flags_score(format_flags, fbconfigs[i].format_flags);
+        if (best_score < 0 || score <= best_score) {
+            best_score = score;
+            best_config = i;
+        }
+    }
+
+    if (best_score > 0) {
+        DEBUGF("Got format flags %04x but we couldn't find an exactly matching "
+                        "config, chose %d\n", format_flags, best_config);
+    }
+
+    return best_config;
+}
+
+static int glXGetConfigFunc(uint32_t visualid, uint32_t attrib, uint32_t *value)
+{
+    const VmglGLXFBConfig *config = &fbconfigs[0];
+
+    if (visualid < ARRAY_SIZE(fbconfigs)) {
+        config = &fbconfigs[visualid];
+    } else {
+        DEBUGF("Unknown visual ID %d\n", visualid);
+    }
+
+    if (value) {
+        *value = glo_get_glx_from_flags(config->format_flags, attrib);
+    }
+
+    return 0;
+}
+
+static const VmglGLXFBConfig *glXGetFBConfigsFunc(uint32_t screen,
+                uint32_t *nelements)
+{
+    *nelements = ARRAY_SIZE(fbconfigs);
+    return &fbconfigs[0];
+}
+
+static int glXGetFBConfigAttribFunc(const VmglGLXFBConfig *fbconfig,
+                uint32_t attrib, uint32_t *value)
+{
+    /* TODO other enums -
+     * see http://www.opengl.org/sdk/docs/man/xhtml/glXGetFBConfigAttrib.xml */
+    if (value) {
+        *value = glo_get_glx_from_flags(fbconfig->format_flags, attrib);
+    }
+
+    return 0;
+}
+
+static const VmglGLXFBConfig *glXChooseFBConfigFunc(uint32_t screen,
+                const uint32_t *attrib_list, uint32_t *nelements)
+{
+    if (attrib_list == NULL) {
+        if (nelements) {
+            *nelements = 0;
+        }
+
+        return 0;
+    }
+
+    int format_flags = glo_flags_get_from_glx(attrib_list, 0);
+    int i;
+    int best_config = 0;
+    int best_score = -1;
+
+    for (i = 0; i < ARRAY_SIZE(fbconfigs); i++) {
+        int score = glo_flags_score(format_flags, fbconfigs[i].format_flags);
+        if (best_score < 0 || score <= best_score) {
+            best_score = score;
+            best_config = i;
+        }
+    }
+
+    if (best_score > 0) {
+        DEBUGF("Got format flags %d but we couldn't find an exactly "
+                        "matching config, chose %d\n",
+                        format_flags, best_config);
+    }
+
+    if (nelements) {
+        *nelements = 1;
+    }
+
+    return &fbconfigs[best_config];
+}
+
+static void do_glClientActiveTextureARB(GLint texture)
+{
+    GET_EXT_PTR_NO_FAIL(void, glClientActiveTextureARB, (GLint));
+
+    if (ptr_func_glClientActiveTextureARB) {
+        ptr_func_glClientActiveTextureARB(texture);
+    }
+}
+
+static void destroy_gl_state(GLState *state)
+{
+    int i;
+    QGloSurface *qsurface, *tmp;
+
+    QTAILQ_FOREACH_SAFE(qsurface, &state->qsurfaces, next, tmp) {
+        glo_surface_destroy(qsurface->surface);
+        QTAILQ_REMOVE(&state->qsurfaces, qsurface, next);
+        g_free(qsurface);
+    }
+
+    if (state->context) {
+        glo_context_destroy(state->context);
+    }
+
+    if (state->vertexPointer) {
+        g_free(state->vertexPointer);
+    }
+    if (state->normalPointer) {
+        g_free(state->normalPointer);
+    }
+    if (state->indexPointer) {
+        g_free(state->indexPointer);
+    }
+    if (state->colorPointer) {
+        g_free(state->colorPointer);
+    }
+    if (state->secondaryColorPointer) {
+        g_free(state->secondaryColorPointer);
+    }
+    for (i = 0; i < NB_MAX_TEXTURES; i++) {
+        if (state->texCoordPointer[i]) {
+            g_free(state->texCoordPointer[i]);
+        }
+    }
+    for (i = 0; i < MY_GL_MAX_VERTEX_ATTRIBS_ARB; i++) {
+        if (state->vertexAttribPointer[i]) {
+            g_free(state->vertexAttribPointer[i]);
+        }
+    }
+    for (i = 0; i < MY_GL_MAX_VERTEX_ATTRIBS_NV; i++) {
+        if (state->vertexAttribPointerNV[i]) {
+            g_free(state->vertexAttribPointerNV[i]);
+        }
+    }
+    if (state->weightPointer) {
+        g_free(state->weightPointer);
+    }
+    if (state->matrixIndexPointer) {
+        g_free(state->matrixIndexPointer);
+    }
+    if (state->fogCoordPointer) {
+        g_free(state->fogCoordPointer);
+    }
+    for (i = 0; i < MY_GL_MAX_VARIANT_POINTER_EXT; i++) {
+        if (state->variantPointerEXT[i]) {
+            g_free(state->variantPointerEXT[i]);
+        }
+    }
+    if (state->interleavedArrays) {
+        g_free(state->interleavedArrays);
+    }
+    if (state->elementPointerATI) {
+        g_free(state->elementPointerATI);
+    }
+    if (state->own_indices) {
+        g_free(state->own_indices);
+    }
+}
+
+static void init_gl_state(GLState *state)
+{
+    state->texture_allocator = &state->own_texture_allocator;
+    state->tab_textures = state->own_tab_textures;
+    state->buffer_allocator = &state->own_buffer_allocator;
+    state->tab_buffers = state->own_tab_buffers;
+    state->list_allocator = &state->own_list_allocator;
+    state->tab_lists = state->own_tab_lists;
+}
+
+/* Translate the nth element of list from type to GLuint.  */
+static GLuint translate_id(GLsizei n, GLenum type, const GLvoid *list)
+{
+    GLbyte *b_ptr;
+    GLubyte *ub_ptr;
+    GLshort *s_ptr;
+    GLushort *us_ptr;
+    GLint *i_ptr;
+    GLuint *ui_ptr;
+    GLfloat *f_ptr;
+
+    switch (type) {
+    case GL_BYTE:
+        b_ptr = (GLbyte *) list;
+        return (GLuint) *(b_ptr + n);
+    case GL_UNSIGNED_BYTE:
+        ub_ptr = (GLubyte *) list;
+        return (GLuint) *(ub_ptr + n);
+    case GL_SHORT:
+        s_ptr = (GLshort *) list;
+        return (GLuint) *(s_ptr + n);
+    case GL_UNSIGNED_SHORT:
+        us_ptr = (GLushort *) list;
+        return (GLuint) *(us_ptr + n);
+    case GL_INT:
+        i_ptr = (GLint *) list;
+        return (GLuint) *(i_ptr + n);
+    case GL_UNSIGNED_INT:
+        ui_ptr = (GLuint *) list;
+        return (GLuint) *(ui_ptr + n);
+    case GL_FLOAT:
+        f_ptr = (GLfloat *) list;
+        return (GLuint) *(f_ptr + n);
+    case GL_2_BYTES:
+        ub_ptr = ((GLubyte *) list) + 2 * n;
+        return (GLuint) (*ub_ptr << 8) + (GLuint) *(ub_ptr + 1);
+    case GL_3_BYTES:
+        ub_ptr = ((GLubyte *) list) + 3 * n;
+        return (GLuint) (*ub_ptr << 16) + (GLuint) (*(ub_ptr + 1) << 8) +
+            (GLuint) *(ub_ptr + 2);
+    case GL_4_BYTES:
+        ub_ptr = ((GLubyte *) list) + 4 * n;
+        return (GLuint) (*ub_ptr << 24) + (GLuint) (*(ub_ptr + 1) << 16) +
+            (GLuint) (*(ub_ptr + 2) << 8) + (GLuint) *(ub_ptr + 3);
+    default:
+        return 0;
+    }
+}
+
+static GLState *create_context(ProcessState *process,
+                int fake_ctxt, int fake_share_list)
+{
+    process->glstates = g_realloc(process->glstates,
+                    (process->nb_states + 1) * sizeof(GLState *));
+
+    process->glstates[process->nb_states] = g_malloc0(sizeof(GLState));
+
+    process->glstates[process->nb_states]->ref = 1;
+    process->glstates[process->nb_states]->fake_ctxt = fake_ctxt;
+    process->glstates[process->nb_states]->fake_share_list = fake_share_list;
+
+    init_gl_state(process->glstates[process->nb_states]);
+
+    if (fake_share_list) {
+        int i;
+
+        for (i = 0; i < process->nb_states; i++) {
+            if (process->glstates[i]->fake_ctxt == fake_share_list) {
+                break;
+            }
+        }
+        if (i < process->nb_states) {
+            process->glstates[i]->ref++;
+            process->glstates[process->nb_states]->texture_allocator =
+                process->glstates[i]->texture_allocator;
+            process->glstates[process->nb_states]->tab_textures =
+                process->glstates[i]->tab_textures;
+            process->glstates[process->nb_states]->buffer_allocator =
+                process->glstates[i]->buffer_allocator;
+            process->glstates[process->nb_states]->tab_buffers =
+                process->glstates[i]->tab_buffers;
+            process->glstates[process->nb_states]->list_allocator =
+                process->glstates[i]->list_allocator;
+            process->glstates[process->nb_states]->tab_lists =
+                process->glstates[i]->tab_lists;
+        }
+    }
+    process->nb_states++;
+
+    return process->glstates[process->nb_states - 1];
+}
+
+static GLState *get_glstate_for_fake_ctxt(ProcessState *process, int fake_ctxt)
+{
+    int i;
+
+    for (i = 0; i < process->nb_states; i++) {
+        if (process->glstates[i]->fake_ctxt == fake_ctxt) {
+            return process->glstates[i];
+        }
+    }
+
+    return 0;
+}
+
+void vmgl_disconnect(ProcessStruct *p)
+{
+    ProcessState *process = DO_UPCAST(ProcessState, p, p);
+    int i;
+
+    for (i = 0; i < process->nb_states; i++) {
+        destroy_gl_state(process->glstates[i]);
+        g_free(process->glstates[i]);
+    }
+
+    destroy_gl_state(&process->default_state);
+    g_free(process->glstates);
+
+    for (i = 0; &processes[i] != process; i++) {
+        memmove(&processes[i], &processes[i + 1],
+                        (MAX_HANDLED_PROCESS - 1 - i) * sizeof(ProcessState));
+    }
+}
+
+ProcessStruct *vmgl_get_process(pid_t pid)
+{
+    ProcessState *process = NULL;
+    static int first;
+    int i;
+
+    if (!first) {
+        first = 1;
+        init_process_tab();
+    }
+
+    /* Look a process struct up. If there isn't one associated with this pid
+     * then we create one.
+     * process->current_state contains info on which of the guests contexts is
+     * current.
+     */
+    for (i = 0; i < MAX_HANDLED_PROCESS; i++) {
+        if (processes[i].p.process_id == pid) {
+            process = &processes[i];
+            break;
+        } else if (processes[i].p.process_id == 0) {
+            process = &processes[i];
+            memset(process, 0, sizeof(ProcessState));
+            process->p.process_id = pid;
+            init_gl_state(&process->default_state);
+            process->current_state = &process->default_state;
+            break;
+        }
+    }
+
+    if (process == NULL) {
+        DEBUGF("Too many processes!\n");
+        exit(-1);
+    }
+
+    return (ProcessStruct *) process; /* Cast is ok due to struct defn. */
+}
+
+static void vmgl_context_switch(ProcessStruct *p, int switch_gl_context)
+{
+    ProcessState *process = DO_UPCAST(ProcessState, p, p);
+    if (switch_gl_context) {
+        if (process->current_state->current_qsurface) {
+            glo_surface_makecurrent(process->current_state->
+                            current_qsurface->surface);
+        } else {
+            glo_surface_makecurrent(0); /* should never happen */
+        }
+    }
+}
+
+static int sizeof_gl_type(int type)
+{
+    switch (type) {
+    case GL_BYTE:
+    case GL_UNSIGNED_BYTE:
+        return 1;
+    case GL_SHORT:
+    case GL_UNSIGNED_SHORT:
+        return 2;
+    case GL_INT:
+    case GL_UNSIGNED_INT:
+    case GL_FLOAT:
+        return 4;
+    case GL_DOUBLE:
+        return 8;
+    default:
+        return 0;
+    }
+};
+
+static int check_arrays(ProcessState *process, int max_elem, int disable)
+{
+    int i;
+    GET_EXT_PTR(void, glDisableVertexAttribArray, (GLuint));
+
+    for (i = 0; i < MY_GL_MAX_VERTEX_ATTRIBS_ARB; i++) {
+        if (process->current_state->vertexAttrib_enabled[i] &&
+                max_elem >= process->current_state->vertexAttrib_count[i]) {
+            fprintf(stderr, "vmgl error: Array %i force-disabled\n", i);
+            if (disable) {
+                ptr_func_glDisableVertexAttribArray(i);
+            } else {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int do_function_call(ProcessState *process, int func_number,
+                arg_t *args, uint8_t *ret_buffer)
+{
+    union gl_ret_type ret;
+    Signature *signature = (Signature *) tab_opengl_calls[func_number];
+    int ret_type = signature->ret_type;
+
+    ret.s = NULL;
+
+    if (display_function_call) {
+        DEBUGF("[%d]> %s\n", process->p.process_id,
+                        tab_opengl_calls_name[func_number]);
+    }
+
+    switch (func_number) {
+    case -1:
+        break;
+
+    case vmgl_resize_surface_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[0]);
+            QGloSurface *qsurface;
+
+            if (!client_drawable) {
+                return 0;
+            }
+
+            qsurface = get_qsurface_from_client_drawable(
+                            process->current_state, client_drawable);
+
+            /* We have to assume the current context here since we assume
+             * that a drawable must belong to a specific context */
+            if (!resize_surface(process, qsurface,
+                            args[1], args[2])) {
+                return 0;
+            }
+            break;
+        }
+
+    case vmgl_render_surface_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[0]);
+            QGloSurface *qsurface;
+            int bpp    = (int) args[1];
+            int stride = (int) args[2];
+            uint8_t *render_buffer = (uint8_t *) args[3];
+
+            if (!client_drawable) {
+                return 0;
+            }
+
+            qsurface = get_qsurface_from_client_drawable(
+                            process->current_state, client_drawable);
+
+            /* We have to assume the current context here since we assume
+             * that a drawable must belong to a specific context */
+            render_surface(qsurface, bpp, stride, render_buffer);
+            break;
+        }
+
+    case glXWaitGL_func:
+        glFinish(); /* glXWaitGL(); */
+        ret.i = 0;
+        break;
+
+    case glXWaitX_func:
+        ret.i = 0;
+        break;
+
+    case glXChooseVisual_func:
+        ret.i = glXChooseVisualFunc((uint32_t *) &args[2]);
+        break;
+
+    case glXQueryExtensionsString_func:
+        ret.s = supported_glx_extensions();
+        break;
+
+    case glXQueryServerString_func:
+        switch (args[2]) {
+        case GLX_VENDOR:
+            ret.s = FAKE_GLX_VENDOR;
+            break;
+        case GLX_VERSION:
+            ret.s = FAKE_GLX_VERSION_STRING;
+            break;
+        case GLX_EXTENSIONS:
+            ret.s = supported_glx_extensions();
+            break;
+        default:
+            ret.s = 0;
+        }
+        break;
+
+    case glXGetClientString_func:
+        switch (args[1]) {
+        case GLX_VENDOR:
+            ret.s = FAKE_GLX_VENDOR;
+            break;
+        case GLX_VERSION:
+            ret.s = FAKE_GLX_VERSION_STRING;
+            break;
+        case GLX_EXTENSIONS:
+            ret.s = "GLX_ARB_get_proc_address ";
+            break;
+        default:
+            ret.s = 0;
+        }
+        break;
+
+    case glXGetScreenDriver_func:
+        {
+            /* FIXME Not documented anywhere, previously implemented as
+             * a 1:1 mapping to host glXGetScreenDriver */
+            ret.s = "";
+            break;
+        }
+
+    case glXGetDriverConfig_func:
+        {
+            /* FIXME Not documented anywhere, previously implemented as
+             * a 1:1 mapping to host glXGetScreenConfig */
+            ret.s = "";
+            break;
+        }
+
+    case glXCreateContext_func:
+        {
+            int visualid = args[1];
+            int fake_share_list = args[2];
+            GLState *share_list_state;
+            int fake_ctxt;
+
+            if (display_function_call) {
+                DEBUGF("visualid=%d, fake_share_list=%d\n", visualid,
+                                fake_share_list);
+            }
+
+            share_list_state = get_glstate_for_fake_ctxt(process,
+                            fake_share_list);
+            fake_ctxt = ++process->next_available_context_number;
+
+            ret.i = fake_ctxt;
+
+            /* Work out format flags from visual id */
+            int format_flags = GLO_FF_DEFAULT;
+            if (visualid >= 0 && visualid < ARRAY_SIZE(fbconfigs)) {
+                format_flags = fbconfigs[visualid].format_flags;
+            }
+
+            GLState *state = create_context(process, fake_ctxt,
+                            fake_share_list);
+            state->context = glo_context_create(format_flags,
+                            (GloContext *) share_list_state ?
+                            share_list_state->context : 0);
+            if (!state->context) {
+                return 0;
+            }
+
+            DEBUGF("created context %p for %08x\n", state, fake_ctxt);
+            break;
+        }
+
+    case glXCreateNewContext_func:
+        {
+            uint32_t client_fbconfig = args[1];
+            const VmglGLXFBConfig *fbconfig = get_fbconfig(process,
+                            client_fbconfig);
+
+            ret.i = 0;
+
+            if (fbconfig) {
+                int fake_share_list = args[3];
+                int fake_ctxt;
+                GLState *state;
+                GLState *share_list_state = get_glstate_for_fake_ctxt(process,
+                                fake_share_list);
+
+                process->next_available_context_number++;
+                fake_ctxt = process->next_available_context_number;
+                ret.i = fake_ctxt;
+
+                state = create_context(process, fake_ctxt, fake_share_list);
+                /* TODO: retrieve from fbconfig */
+                state->context = glo_context_create(fbconfig->format_flags,
+                                share_list_state ?
+                                share_list_state->context : 0);
+                if (!state->context) {
+                    return 0;
+                }
+            }
+            break;
+        }
+
+    case glXCopyContext_func:
+        DEBUGF(" glXCopyContext not supported (does anything use it?)\n");
+        break;
+
+    case glXDestroyContext_func:
+        {
+            int fake_ctxt = (int) args[1];
+            int i;
+            int fake_share_list;
+
+            if (display_function_call) {
+                DEBUGF("fake_ctxt=%d\n", fake_ctxt);
+            }
+
+            for (i = 0; i < process->nb_states; i++) {
+                if (process->glstates[i]->fake_ctxt == fake_ctxt) {
+                    /* this was our GLState... */
+                    break;
+                }
+            }
+
+            process->current_state = &process->default_state;
+
+            fake_share_list = process->glstates[i]->fake_share_list;
+            process->glstates[i]->ref--;
+
+            if (process->glstates[i]->ref == 0) {
+                DEBUGF("destroy_gl_state fake_ctxt = %d\n",
+                                process->glstates[i]->fake_ctxt);
+                destroy_gl_state(process->glstates[i]);
+                g_free(process->glstates[i]);
+                memmove(&process->glstates[i],
+                                &process->glstates[i + 1],
+                                (process->nb_states - i - 1) *
+                                sizeof(GLState *));
+                process->nb_states--;
+            }
+
+            if (!fake_share_list) {
+                break;
+            }
+
+            for (i = 0; i < process->nb_states; i++) {
+                if (process->glstates[i]->fake_ctxt == fake_share_list) {
+                    break;
+                }
+            }
+
+            if (--process->glstates[i]->ref) {
+                break;
+            }
+
+            DEBUGF("destroy_gl_state fake_ctxt = %d\n",
+                            process->glstates[i]->fake_ctxt);
+            destroy_gl_state(process->glstates[i]);
+            g_free(process->glstates[i]);
+            memmove(&process->glstates[i], &process->glstates[i + 1],
+                            (process->nb_states - i - 1) * sizeof(GLState *));
+            process->nb_states--;
+
+            break;
+        }
+
+    case glXQueryVersion_func:
+        {
+            uint32_t *major = (uint32_t *) args[1];
+            uint32_t *minor = (uint32_t *) args[2];
+#if 0
+            ret.i = glXQueryVersion(dpy, (uint32_t *) args[1],
+                            (uint32_t *) args[2]);
+#else
+            if (major) {
+                *major = FAKE_GLX_VERSION_MAJOR;
+            }
+            if (minor) {
+                *minor = FAKE_GLX_VERSION_MINOR;
+            }
+            ret.i = 1;
+#endif
+            break;
+        }
+
+    case glGetString_func:
+        switch (args[0]) {
+        case GL_VENDOR:
+            ret.s = FAKE_GL_VENDOR;
+            break;
+        case GL_RENDERER:
+            ret.s = FAKE_GL_RENDERER;
+            break;
+        case GL_VERSION:
+            ret.s = FAKE_GL_VERSION;
+            break;
+        case GL_EXTENSIONS:
+            ret.s = compute_gl_extensions();
+            break;
+        case GL_SHADING_LANGUAGE_VERSION:
+            if (FAKE_GL_MAJOR < 2) {
+                ret.s = "";
+                break;
+            }
+            /* Fall through.  */
+        default:
+            ret.s = (char *) glGetString(args[0]);
+            break;
+        }
+        break;
+
+    case glXMakeCurrent_func:
+        {
+            ClientGLXDrawable client_drawable = to_drawable(args[1]);
+            int fake_ctxt = (int) args[2];
+            GLState *glstate = NULL;
+
+            DEBUGF("Makecurrent: fake_ctx=%d client_drawable=%p\n",
+                            fake_ctxt, client_drawable);
+
+            if (client_drawable == 0 && fake_ctxt == 0) {
+                /* Release context */
+                if (process->current_state->current_qsurface) {
+                    process->current_state->current_qsurface->ref--;
+                }
+                process->current_state = &process->default_state;
+
+                glo_surface_makecurrent(0);
+            } else { /* Look up GLState struct for this context */
+                glstate = get_glstate_for_fake_ctxt(process, fake_ctxt);
+                if (!glstate) {
+                    DEBUGF(" --invalid fake_ctxt (%d)!\n", fake_ctxt);
+                } else {
+                    if (!set_current_qsurface(glstate, client_drawable)) {
+                        /* If there is no surface, create one.  */
+                        QGloSurface *qsurface = g_new(QGloSurface, 1);
+                        qsurface->surface = glo_surface_create(4, 4,
+                                        glstate->context);
+                        qsurface->client_drawable = client_drawable;
+                        qsurface->ref = 1;
+
+                        if (!qsurface->surface) {
+                            free(qsurface);
+                            return 0;
+                        }
+
+                        bind_qsurface(glstate, qsurface);
+                        DEBUGF(" --Client drawable not found, create new "
+                                        "surface: %p %p\n", qsurface,
+                                        client_drawable);
+                    } else {
+                        DEBUGF(" --Client drawable found, using surface: "
+                                        "%p %p\n",
+                                        glstate->current_qsurface,
+                                        client_drawable);
+                    }
+
+                    process->current_state = glstate;
+
+                    ret.i = glo_surface_makecurrent(
+                                    glstate->current_qsurface->surface);
+                }
+            }
+            break;
+        }
+
+    case glXSwapBuffers_func:
+        /* Does nothing - window data is copied via render_surface() */
+        break;
+
+    case glXIsDirect_func:
+        {
+            /* int fake_ctxt = (int) args[1]; */
+
+            /* Does this go direct and skip the X server?  It does skip
+             * the guest X serever, so we'll just say yes for now.  */
+            ret.c = 1;
+
+            break;
+        }
+
+    case glXGetConfig_func:
+        {
+            int visualid = args[1];
+
+            ret.i = glXGetConfigFunc(visualid, args[2], (uint32_t *) args[3]);
+            break;
+        }
+
+    case glXGetConfig_extended_func:
+        {
+            int visualid = args[1];
+            int n = args[2];
+            int i;
+            uint32_t *attribs = (uint32_t *) args[3];
+            uint32_t *values = (uint32_t *) args[4];
+            uint32_t *res = (uint32_t *) args[5];
+
+            for (i = 0; i < n; i++) {
+                res[i] = glXGetConfigFunc(visualid, attribs[i], &values[i]);
+            }
+            break;
+        }
+
+    case glXUseXFont_func:
+        /* implementation is client-side only :-) */
+        break;
+
+    case glXQueryExtension_func:
+        {
+            uint32_t *errorBase = (uint32_t *) args[1];
+            uint32_t *eventBase = (uint32_t *) args[2];
+
+            if (errorBase) {
+                *errorBase = 0; /* FIXME */
+            }
+            if (eventBase) {
+                *eventBase = 0; /* FIXME */
+            }
+            ret.i = 1;
+            break;
+        }
+
+    case glXChooseFBConfig_func:
+        if (process->nfbconfig == MAX_FBCONFIG) {
+            *(uint32_t *) args[3] = 0;
+            ret.i = 0;
+        } else {
+            const VmglGLXFBConfig *fbconfigs =
+                glXChooseFBConfigFunc(args[1],
+                                (uint32_t *) args[2], (uint32_t *) args[3]);
+
+            if (fbconfigs) {
+                process->fbconfigs[process->nfbconfig] = fbconfigs;
+                process->fbconfigs_max[process->nfbconfig] =
+                    *(uint32_t *) args[3];
+                process->nfbconfig++;
+                ret.i = 1 + process->nfbconfig_total;
+                process->nfbconfig_total +=
+                    process->fbconfigs_max[process->nfbconfig];
+            } else {
+                ret.i = 0;
+            }
+        }
+        break;
+
+    case glXGetFBConfigs_func:
+        if (process->nfbconfig == MAX_FBCONFIG) {
+            *(uint32_t *) args[2] = 0;
+            ret.i = 0;
+        } else {
+            const VmglGLXFBConfig *fbconfigs =
+                glXGetFBConfigsFunc(args[1], (uint32_t *) args[2]);
+
+            if (fbconfigs) {
+                process->fbconfigs[process->nfbconfig] = fbconfigs;
+                process->fbconfigs_max[process->nfbconfig] =
+                    *(uint32_t *) args[2];
+                process->nfbconfig++;
+                ret.i = 1 + process->nfbconfig_total;
+                process->nfbconfig_total +=
+                    process->fbconfigs_max[process->nfbconfig];
+            } else {
+                ret.i = 0;
+            }
+        }
+        break;
+
+    case glXGetFBConfigAttrib_func:
+        {
+            uint32_t client_fbconfig = args[1];
+            const VmglGLXFBConfig *fbconfig;
+
+            ret.i = 0;
+            fbconfig = get_fbconfig(process, client_fbconfig);
+
+            if (fbconfig) {
+                ret.i = glXGetFBConfigAttribFunc(fbconfig,
+                                args[2], (uint32_t *) args[3]);
+            }
+            break;
+        }
+
+    case glXGetFBConfigAttrib_extended_func:
+        {
+            uint32_t client_fbconfig = args[1];
+            int n = args[2];
+            int i;
+            uint32_t *attribs = (uint32_t *) args[3];
+            uint32_t *values = (uint32_t *) args[4];
+            uint32_t *res = (uint32_t *) args[5];
+            const VmglGLXFBConfig *fbconfig =
+                get_fbconfig(process, client_fbconfig);
+
+            for (i = 0; i < n; i++) {
+                if (fbconfig) {
+                    res[i] = glXGetFBConfigAttribFunc(fbconfig,
+                                    attribs[i], &values[i]);
+                } else {
+                    res[i] = 0;
+                }
+            }
+            break;
+        }
+
+    case glXQueryContext_func:
+        /* TODO (previously implemented using get_association_fakectx_glxctx) */
+        DEBUGF("glXQueryContext not implemented\n");
+        ret.i = 0;
+        break;
+
+    case glXQueryDrawable_func:
+        /* TODO one of:
+         * GLX_WIDTH, GLX_HEIGHT, GLX_PRESERVED_CONTENTS,
+         * GLX_LARGEST_PBUFFER, GLX_FBCONFIG_ID
+         * (previously implemented with
+         *  get_association_clientdrawable_serverdrawable) */
+        DEBUGF("FIXME: glXQueryDrawable not implemented\n");
+        ret.i = 0;
+        break;
+
+    case glXGetVisualFromFBConfig_func:
+        {
+            uint32_t client_fbconfig = args[1];
+            const VmglGLXFBConfig *fbconfig;
+
+            ret.i = 0;
+            fbconfig = get_fbconfig(process, client_fbconfig);
+
+            if (!fbconfig) {
+                break;
+            }
+
+            /* We treat visualid as the index into the fbconfigs array */
+            ret.i = &fbconfigs[0] - fbconfig;
+            if (display_function_call) {
+                DEBUGF("visualid = %d\n", ret.i);
+            }
+            break;
+        }
+    case glXSwapIntervalSGI_func:
+        {
+            /* Unimplemented */
+            ret.i = 0;
+            break;
+        }
+
+    case glXGetProcAddress_fake_func:
+        {
+            if (display_function_call) {
+                DEBUGF("glXGetProcAddress %s  ", (char *) args[0]);
+            }
+            ret.i = 0;
+            break;
+        }
+
+    case glXGetProcAddress_global_fake_func:
+        {
+            int elems = args[0];
+            char *huge_buffer = (char *) args[1];
+            char *result = (char *) args[2];
+            int i;
+
+            for (i = 0; i < elems; i++) {
+                int len = strlen(huge_buffer);
+                DEBUGF("glXGetProcAddress_global %s  ", (char *) huge_buffer);
+                result[i] = !!glo_getprocaddress((const char *) huge_buffer);
+                huge_buffer += len + 1;
+            }
+            break;
+        }
+
+    /* Textures */
+    case glBindTexture_func:
+    case glBindTextureEXT_func:
+        {
+            int target = args[0];
+            unsigned int client_texture = args[1];
+            unsigned int server_texture;
+
+            if (client_texture == 0) {
+                glBindTexture(target, 0);
+            } else {
+                alloc_value(process->current_state->texture_allocator,
+                                client_texture);
+                server_texture =
+                    process->current_state->tab_textures[client_texture];
+                if (server_texture == 0) {
+                    glGenTextures(1, &server_texture);
+                    process->current_state->tab_textures[client_texture] =
+                        server_texture;
+                }
+                glBindTexture(target, server_texture);
+            }
+            break;
+        }
+
+    case glGenTextures_fake_func:
+        {
+            GET_EXT_PTR(void, glGenTextures, (GLsizei n, GLuint *textures));
+            int i;
+            int n = args[0];
+            unsigned int *client_tab_textures = g_malloc(n * sizeof(int));
+            unsigned int *server_tab_textures = g_malloc(n * sizeof(int));
+
+            alloc_range(process->current_state->texture_allocator, n,
+                            client_tab_textures);
+
+            ptr_func_glGenTextures(n, server_tab_textures);
+            for (i = 0; i < n; i++) {
+                process->current_state->tab_textures[client_tab_textures[i]] =
+                    server_tab_textures[i];
+            }
+
+            g_free(client_tab_textures);
+            g_free(server_tab_textures);
+            break;
+        }
+
+    case glDeleteTextures_func:
+        {
+            GET_EXT_PTR(void, glDeleteTextures,
+                            (GLsizei n, const GLuint *textures));
+            int i;
+            int n = args[0];
+            uint32_t *client_tab_textures = (uint32_t *) args[1];
+            unsigned int *server_tab_textures = g_malloc(n * sizeof(int));
+
+            delete_range(process->current_state->texture_allocator, n,
+                            client_tab_textures);
+
+            for (i = 0; i < n; i++) {
+                server_tab_textures[i] =
+                    get_server_texture(process, client_tab_textures[i]);
+            }
+            ptr_func_glDeleteTextures(n, server_tab_textures);
+            for (i = 0; i < n; i++) {
+                process->current_state->tab_textures[client_tab_textures[i]] =
+                    0;
+            }
+            g_free(server_tab_textures);
+            break;
+        }
+
+    case glPrioritizeTextures_func:
+        {
+            GET_EXT_PTR(void, glPrioritizeTextures,
+                            (GLsizei n, const GLuint *textures,
+                             const GLclampf *priorities));
+
+            int i;
+            int n = args[0];
+            uint32_t *textures = (uint32_t *) args[1];
+
+            for (i = 0; i < n; i++) {
+                textures[i] = get_server_texture(process, textures[i]);
+            }
+            ptr_func_glPrioritizeTextures(n, textures,
+                            (const GLclampf *) args[2]);
+            break;
+        }
+
+    case glAreTexturesResident_func:
+        {
+            GET_EXT_PTR(void, glAreTexturesResident,
+                            (GLsizei n, const GLuint *textures,
+                             GLboolean *residences));
+            int i;
+            int n = args[0];
+            uint32_t *textures = (uint32_t *) args[1];
+
+            for (i = 0; i < n; i++) {
+                textures[i] = get_server_texture(process, textures[i]);
+            }
+            ptr_func_glAreTexturesResident(n, textures, (GLboolean *) args[2]);
+            break;
+        }
+
+    case glIsTexture_func:
+    case glIsTextureEXT_func:
+        {
+            GET_EXT_PTR(GLboolean, glIsTexture, (GLuint texture));
+            uint32_t client_texture = args[0];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture) {
+                ret.c = ptr_func_glIsTexture(server_texture);
+            } else {
+                ret.c = 0;
+            }
+            break;
+        }
+
+    case glFramebufferTexture1DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture1DEXT,
+                            (int, int, int, int, int));
+            uint32_t client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture) {
+                ptr_func_glFramebufferTexture1DEXT(args[0], args[1], args[2],
+                                server_texture, args[4]);
+            }
+            break;
+        }
+
+    case glFramebufferTexture2D_func:
+    case glFramebufferTexture2DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture2DEXT,
+                            (int, int, int, int, int));
+            unsigned int client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture) {
+                ptr_func_glFramebufferTexture2DEXT(args[0], args[1], args[2],
+                                server_texture, args[4]);
+            }
+            break;
+        }
+
+    case glFramebufferTexture3DEXT_func:
+        {
+            GET_EXT_PTR(void, glFramebufferTexture3DEXT,
+                            (int, int, int, int, int, int));
+            unsigned int client_texture = args[3];
+            unsigned int server_texture =
+                get_server_texture(process, client_texture);
+            if (server_texture) {
+                ptr_func_glFramebufferTexture3DEXT(args[0], args[1], args[2],
+                                server_texture, args[4], args[5]);
+            }
+            break;
+        }
+
+    /* Lists */
+    case glIsList_func:
+        {
+            unsigned int client_list = args[0];
+            unsigned int server_list = get_server_list(process, client_list);
+
+            if (server_list) {
+                ret.c = glIsList(server_list);
+            } else {
+                ret.c = 0;
+            }
+            break;
+        }
+
+    case glDeleteLists_func:
+        {
+            int i;
+            unsigned int first_client = args[0];
+            int n = args[1];
+
+            unsigned int first_server = get_server_list(process, first_client);
+            for (i = 0; i < n; i++) {
+                if (get_server_list(process, first_client + i) !=
+                        first_server + i) {
+                    break;
+                }
+            }
+            if (i == n) {
+                glDeleteLists(first_server, n);
+            } else {
+                for (i = 0; i < n; i++) {
+                    glDeleteLists(get_server_list(process, first_client + i),
+                                    1);
+                }
+            }
+
+            for (i = 0; i < n; i++) {
+                process->current_state->tab_lists[first_client + i] = 0;
+            }
+            delete_consecutive_values(process->current_state->list_allocator,
+                            first_client, n);
+            break;
+        }
+
+    case glGenLists_fake_func:
+        {
+            int i;
+            int n = args[0];
+            unsigned int server_first = glGenLists(n);
+
+            if (server_first) {
+                unsigned int client_first =
+                    alloc_range(process->current_state->list_allocator, n,
+                                    NULL);
+                for (i = 0; i < n; i++) {
+                    process->current_state->tab_lists[client_first + i] =
+                        server_first + i;
+                }
+            }
+            break;
+        }
+
+    case glNewList_func:
+        {
+            unsigned int server_list;
+            unsigned int client_list = args[0];
+            int mode = args[1];
+
+            alloc_value(process->current_state->list_allocator, client_list);
+            server_list = get_server_list(process, client_list);
+
+            if (server_list == 0) {
+                server_list = glGenLists(1);
+                process->current_state->tab_lists[client_list] = server_list;
+            }
+            glNewList(server_list, mode);
+            break;
+        }
+
+    case glCallList_func:
+        {
+            uint32_t client_list = args[0];
+            GLuint server_list = get_server_list(process, client_list);
+
+            glCallList(server_list);
+            break;
+        }
+
+    case glCallLists_func:
+        {
+            int i;
+            int n = args[0];
+            int type = args[1];
+            const GLvoid *lists = (const GLvoid *) args[2];
+            GLuint *new_lists = g_malloc(sizeof(GLuint) * n);
+
+            for (i = 0; i < n; i++) {
+                new_lists[i] =
+                    get_server_list(process, translate_id(i, type, lists));
+            }
+            glCallLists(n, GL_UNSIGNED_INT, new_lists);
+            g_free(new_lists);
+            break;
+        }
+
+    /* Buffers */
+    case glBindBufferARB_func:
+        {
+            GET_EXT_PTR(void, glBindBufferARB, (GLint, GLuint));
+            GLint target = args[0];
+            uint32_t client_buffer = args[1];
+            GLuint server_buffer;
+
+            if (client_buffer == 0) {
+                ptr_func_glBindBufferARB(target, 0);
+            } else {
+                server_buffer = get_server_buffer(process, client_buffer);
+                ptr_func_glBindBufferARB(target, server_buffer);
+            }
+            break;
+        }
+
+    case glGenBuffersARB_fake_func:
+        {
+            GET_EXT_PTR(void, glGenBuffersARB, (GLint, GLuint *));
+            int i;
+            int n = args[0];
+            uint32_t *client_tab_buffers = g_malloc(n * 4);
+            GLuint *server_tab_buffers = g_malloc(n * sizeof(GLuint));
+
+            alloc_range(process->current_state->buffer_allocator, n,
+                            client_tab_buffers);
+
+            ptr_func_glGenBuffersARB(n, server_tab_buffers);
+            for (i = 0; i < n; i++) {
+                process->current_state->tab_buffers[client_tab_buffers[i]] =
+                    server_tab_buffers[i];
+            }
+
+            g_free(client_tab_buffers);
+            g_free(server_tab_buffers);
+            break;
+        }
+
+
+    case glDeleteBuffersARB_func:
+        {
+            GET_EXT_PTR(void, glDeleteBuffersARB, (GLint, GLint *));
+            int i;
+            int n = args[0];
+            uint32_t *client_tab_buffers = (uint32_t *) args[1];
+
+            delete_range(process->current_state->buffer_allocator, n,
+                            client_tab_buffers);
+
+            GLint *server_tab_buffers = g_malloc(n * sizeof(GLint));
+
+            for (i = 0; i < n; i++) {
+                server_tab_buffers[i] =
+                    get_server_buffer(process, client_tab_buffers[i]);
+            }
+            ptr_func_glDeleteBuffersARB(n, server_tab_buffers);
+            for (i = 0; i < n; i++) {
+                process->current_state->tab_buffers[client_tab_buffers[i]] = 0;
+            }
+            g_free(server_tab_buffers);
+            break;
+        }
+
+    case glIsBufferARB_func:
+        {
+            GET_EXT_PTR(int, glIsBufferARB, (GLuint));
+            uint32_t client_buffer = args[0];
+            GLuint server_buffer =
+                get_server_buffer(process, client_buffer);
+            if (server_buffer) {
+                ret.i = ptr_func_glIsBufferARB(server_buffer);
+            } else {
+                ret.i = 0;
+            }
+            break;
+        }
+
+    /* Other */
+    case glShaderSourceARB_fake_func:
+        {
+            GET_EXT_PTR(void, glShaderSourceARB, (int, int, char **, void *));
+            int size = args[1];
+            int i;
+            int acc_length = 0;
+            GLcharARB **tab_prog = g_malloc(size * sizeof(GLcharARB *));
+            uint32_t *tab_length = (uint32_t *) args[3];
+
+            for (i = 0; i < size; i++) {
+                tab_prog[i] = ((GLcharARB *) args[2]) + acc_length;
+                acc_length += tab_length[i];
+            }
+            ptr_func_glShaderSourceARB(args[0], args[1], tab_prog, tab_length);
+            g_free(tab_prog);
+            break;
+        }
+
+    case glShaderSource_fake_func:
+        {
+            GET_EXT_PTR(void, glShaderSource, (int, int, char **, void *));
+            int size = args[1];
+            int i;
+            int acc_length = 0;
+            GLcharARB **tab_prog = g_malloc(size * sizeof(GLcharARB *));
+            uint32_t *tab_length = (uint32_t *) args[3];
+
+            for (i = 0; i < size; i++) {
+                tab_prog[i] = ((GLcharARB *) args[2]) + acc_length;
+                acc_length += tab_length[i];
+            }
+            ptr_func_glShaderSource(args[0], args[1], tab_prog, tab_length);
+            g_free(tab_prog);
+            break;
+        }
+
+    case glVertexPointer_fake_func:
+        {
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset,
+                            (const void *) args[5], bytes_size);
+
+            glVertexPointer(size, type, stride,
+                            process->current_state->vertexPointer);
+            break;
+        }
+
+    case glNormalPointer_fake_func:
+        {
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->normalPointer_size =
+                MAX(process->current_state->normalPointer_size,
+                                offset + bytes_size);
+            process->current_state->normalPointer =
+                g_realloc(process->current_state->normalPointer,
+                                process->current_state->normalPointer_size);
+            memcpy(process->current_state->normalPointer + offset,
+                            (const void *) args[4], bytes_size);
+
+            glNormalPointer(type, stride,
+                            process->current_state->normalPointer);
+            break;
+        }
+
+    case glIndexPointer_fake_func:
+        {
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->indexPointer_size =
+                MAX(process->current_state->indexPointer_size,
+                                offset + bytes_size);
+            process->current_state->indexPointer =
+                g_realloc(process->current_state->indexPointer,
+                                process->current_state->indexPointer_size);
+            memcpy(process->current_state->indexPointer + offset,
+                            (const void *) args[4], bytes_size);
+
+            glIndexPointer(type, stride,
+                            process->current_state->indexPointer);
+            break;
+        }
+
+    case glEdgeFlagPointer_fake_func:
+        {
+            int offset = args[0];
+            int stride = args[1];
+            int bytes_size = args[2];
+
+            process->current_state->edgeFlagPointer_size =
+                MAX(process->current_state->edgeFlagPointer_size,
+                                offset + bytes_size);
+            process->current_state->edgeFlagPointer =
+                g_realloc(process->current_state->edgeFlagPointer,
+                                process->current_state->
+                                edgeFlagPointer_size);
+            memcpy(process->current_state->edgeFlagPointer + offset,
+                            (const void *) args[3], bytes_size);
+
+            glEdgeFlagPointer(stride,
+                            process->current_state->edgeFlagPointer);
+            break;
+        }
+
+    case glVertexAttribPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerARB,
+                            (int, int, int, int, int, void *));
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int normalized = args[4];
+            int stride = args[5];
+            int bytes_size = args[6];
+            int elem_size = stride;
+
+            if (elem_size == 0) {
+                elem_size = size * sizeof_gl_type(type);
+            }
+            if (elem_size < 1) {
+                return 0;
+            }
+
+            /* TODO: find out if glDrawElements will check the buffer size,
+             * or we should just allocate #_of_elements * size * sizeof(type)
+             * with size == 4 and sizeof(type) == 8 to avoid a buffer
+             * overflow potential in case of type mismatch.  */
+
+            process->current_state->vertexAttribPointer_size[index] =
+                MAX(process->current_state->vertexAttribPointer_size[index],
+                                offset + bytes_size);
+            process->current_state->vertexAttrib_count[index] =
+                (offset + bytes_size) / elem_size;
+            process->current_state->vertexAttribPointer[index] =
+                g_realloc(process->current_state->vertexAttribPointer[
+                                index], process->current_state->
+                                vertexAttribPointer_size[index]);
+            memcpy(process->current_state->vertexAttribPointer[index] +
+                            offset, (const void *) args[7], bytes_size);
+
+            ptr_func_glVertexAttribPointerARB(index, size, type, normalized,
+                            stride,
+                            process->current_state->vertexAttribPointer[index]);
+            break;
+        }
+
+    case glVertexAttribPointerNV_fake_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerNV,
+                            (int, int, int, int, void *));
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int stride = args[4];
+            int bytes_size = args[5];
+
+            process->current_state->vertexAttribPointerNV_size[index] =
+                MAX(process->current_state->vertexAttribPointerNV_size[
+                                index], offset + bytes_size);
+            process->current_state->vertexAttribPointerNV[index] =
+                g_realloc(process->current_state->vertexAttribPointerNV[
+                                index], process->current_state->
+                                vertexAttribPointerNV_size[index]);
+            memcpy(process->current_state->vertexAttribPointerNV[index] +
+                            offset, (const void *) args[6], bytes_size);
+
+            ptr_func_glVertexAttribPointerNV(index, size, type, stride,
+                            process->current_state->
+                            vertexAttribPointerNV[index]);
+            break;
+        }
+
+    case glEnableVertexAttribArrayARB_func:
+    case glEnableVertexAttribArray_func:
+        {
+            uint32_t i = args[0];
+            GET_EXT_PTR(void, glEnableVertexAttribArray, (GLuint));
+
+            if (i >= MY_GL_MAX_VERTEX_ATTRIBS_ARB) {
+                return 0;
+            }
+
+            process->current_state->vertexAttrib_enabled[i] = 1;
+
+            ptr_func_glEnableVertexAttribArray(i);
+            break;
+        }
+
+    case glDisableVertexAttribArrayARB_func:
+    case glDisableVertexAttribArray_func:
+        {
+            uint32_t i = args[0];
+            GET_EXT_PTR(void, glDisableVertexAttribArray, (GLuint));
+
+            if (i >= MY_GL_MAX_VERTEX_ATTRIBS_ARB) {
+                return 0;
+            }
+
+            process->current_state->vertexAttrib_enabled[i] = 0;
+
+            ptr_func_glDisableVertexAttribArray(i);
+            break;
+        }
+
+    case glColorPointer_fake_func:
+        {
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->colorPointer_size =
+                MAX(process->current_state->colorPointer_size,
+                                offset + bytes_size);
+            process->current_state->colorPointer =
+                g_realloc(process->current_state->colorPointer,
+                                process->current_state->colorPointer_size);
+            memcpy(process->current_state->colorPointer + offset,
+                            (const void *) args[5], bytes_size);
+
+            glColorPointer(size, type, stride,
+                            process->current_state->colorPointer);
+            break;
+        }
+
+    case glSecondaryColorPointer_fake_func:
+        {
+            GET_EXT_PTR(void, glSecondaryColorPointer,
+                            (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->secondaryColorPointer_size =
+                MAX(process->current_state->secondaryColorPointer_size,
+                                offset + bytes_size);
+            process->current_state->secondaryColorPointer =
+                g_realloc(process->current_state->secondaryColorPointer,
+                                process->current_state->
+                                secondaryColorPointer_size);
+            memcpy(process->current_state->secondaryColorPointer + offset,
+                            (const void *) args[5], bytes_size);
+
+            ptr_func_glSecondaryColorPointer(size, type, stride,
+                            process->current_state->secondaryColorPointer);
+            break;
+        }
+
+    case glPushClientAttrib_func:
+        {
+            uint32_t mask = args[0];
+
+            if (process->current_state->client_state_sp <
+                    MAX_CLIENT_STATE_STACK_SIZE) {
+                process->current_state->client_state_stack[
+                        process->current_state->client_state_sp].mask = mask;
+                if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
+                    process->current_state->client_state_stack[
+                            process->current_state->client_state_sp].
+                            active_texture_idx =
+                        process->current_state->active_texture_idx;
+                }
+                process->current_state->client_state_sp++;
+            }
+            glPushClientAttrib(mask);
+            break;
+        }
+
+    case glPopClientAttrib_func:
+        if (process->current_state->client_state_sp > 0) {
+            process->current_state->client_state_sp--;
+            if (process->current_state->client_state_stack[
+                    process->current_state->client_state_sp].mask &
+                    GL_CLIENT_VERTEX_ARRAY_BIT) {
+                process->current_state->active_texture_idx =
+                    process->current_state->client_state_stack[process->
+                            current_state->client_state_sp].active_texture_idx;
+            }
+        }
+        glPopClientAttrib();
+        break;
+
+    case glClientActiveTexture_func:
+    case glClientActiveTextureARB_func:
+        {
+            GLint active_texture = args[0];
+
+            process->current_state->active_texture_idx =
+                active_texture - GL_TEXTURE0_ARB;
+            do_glClientActiveTextureARB(active_texture);
+            break;
+        }
+
+    case glTexCoordPointer_fake_func:
+        {
+            int offset = args[0];
+            int index = args[1];
+            int size = args[2];
+            int type = args[3];
+            int stride = args[4];
+            int bytes_size = args[5];
+
+            process->current_state->texCoordPointer_size[index] =
+                MAX(process->current_state->texCoordPointer_size[index],
+                                offset + bytes_size);
+            process->current_state->texCoordPointer[index] =
+                g_realloc(process->current_state->texCoordPointer[index],
+                                process->current_state->
+                                texCoordPointer_size[index]);
+            memcpy(process->current_state->texCoordPointer[index] + offset,
+                            (const void *) args[6], bytes_size);
+
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + index);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[index]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glWeightPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glWeightPointerARB, (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->weightPointer_size =
+                MAX(process->current_state->weightPointer_size,
+                                offset + bytes_size);
+            process->current_state->weightPointer =
+                g_realloc(process->current_state->weightPointer,
+                                process->current_state->weightPointer_size);
+            memcpy(process->current_state->weightPointer + offset,
+                            (const void *) args[5], bytes_size);
+
+            ptr_func_glWeightPointerARB(size, type, stride,
+                            process->current_state->weightPointer);
+            break;
+        }
+
+    case glMatrixIndexPointerARB_fake_func:
+        {
+            GET_EXT_PTR(void, glMatrixIndexPointerARB,
+                            (int, int, int, void *));
+            int offset = args[0];
+            int size = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->matrixIndexPointer_size =
+                MAX(process->current_state->matrixIndexPointer_size,
+                                offset + bytes_size);
+            process->current_state->matrixIndexPointer =
+                g_realloc(process->current_state->matrixIndexPointer,
+                                process->current_state->
+                                matrixIndexPointer_size);
+            memcpy(process->current_state->matrixIndexPointer + offset,
+                            (const void *) args[5], bytes_size);
+
+            ptr_func_glMatrixIndexPointerARB(size, type, stride,
+                            process->current_state->matrixIndexPointer);
+            break;
+        }
+
+    case glFogCoordPointer_fake_func:
+        {
+            GET_EXT_PTR(void, glFogCoordPointer, (int, int, void *));
+            int offset = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->fogCoordPointer_size =
+                MAX(process->current_state->fogCoordPointer_size,
+                                offset + bytes_size);
+            process->current_state->fogCoordPointer =
+                g_realloc(process->current_state->fogCoordPointer,
+                                process->current_state->
+                                fogCoordPointer_size);
+            memcpy(process->current_state->fogCoordPointer + offset,
+                            (const void *) args[4], bytes_size);
+
+            ptr_func_glFogCoordPointer(type, stride,
+                            process->current_state->fogCoordPointer);
+            break;
+        }
+
+    case glVariantPointerEXT_fake_func:
+        {
+            GET_EXT_PTR(void, glVariantPointerEXT, (int, int, int, void *));
+            int offset = args[0];
+            int id = args[1];
+            int type = args[2];
+            int stride = args[3];
+            int bytes_size = args[4];
+
+            process->current_state->variantPointerEXT_size[id] =
+                MAX(process->current_state->variantPointerEXT_size[id],
+                                offset + bytes_size);
+            process->current_state->variantPointerEXT[id] =
+                g_realloc(process->current_state->variantPointerEXT[id],
+                                process->current_state->
+                                variantPointerEXT_size[id]);
+            memcpy(process->current_state->variantPointerEXT[id] + offset,
+                            (const void *) args[5], bytes_size);
+
+            ptr_func_glVariantPointerEXT(id, type, stride,
+                            process->current_state->variantPointerEXT[id]);
+            break;
+        }
+
+    case glInterleavedArrays_fake_func:
+        {
+            GET_EXT_PTR(void, glInterleavedArrays, (int, int, void *));
+            int offset = args[0];
+            int format = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->interleavedArrays_size =
+                MAX(process->current_state->interleavedArrays_size,
+                                offset + bytes_size);
+            process->current_state->interleavedArrays =
+                g_realloc(process->current_state->interleavedArrays,
+                                process->current_state->
+                                interleavedArrays_size);
+            memcpy(process->current_state->interleavedArrays + offset,
+                            (const void *) args[4], bytes_size);
+
+            ptr_func_glInterleavedArrays(format, stride,
+                            process->current_state->interleavedArrays);
+            break;
+        }
+
+    case glElementPointerATI_fake_func:
+        {
+            GET_EXT_PTR(void, glElementPointerATI, (int, void *));
+            int type = args[0];
+            int bytes_size = args[1];
+
+            process->current_state->elementPointerATI_size = bytes_size;
+            process->current_state->elementPointerATI =
+                g_realloc(process->current_state->elementPointerATI,
+                                process->current_state->elementPointerATI_size);
+            memcpy(process->current_state->elementPointerATI,
+                            (const void *) args[2], bytes_size);
+
+            ptr_func_glElementPointerATI(type,
+                            process->current_state->elementPointerATI);
+            break;
+        }
+
+    case glTexCoordPointer01_fake_func:
+        {
+            int size = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->texCoordPointer_size[0] = bytes_size;
+            process->current_state->texCoordPointer[0] =
+                g_realloc(process->current_state->texCoordPointer[0],
+                                bytes_size);
+            memcpy(process->current_state->texCoordPointer[0],
+                            (const void *) args[4], bytes_size);
+
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glTexCoordPointer012_fake_func:
+        {
+            int size = args[0];
+            int type = args[1];
+            int stride = args[2];
+            int bytes_size = args[3];
+
+            process->current_state->texCoordPointer_size[0] = bytes_size;
+            process->current_state->texCoordPointer[0] =
+                g_realloc(process->current_state->texCoordPointer[0],
+                                bytes_size);
+            memcpy(process->current_state->texCoordPointer[0],
+                            (const void *) args[4], bytes_size);
+
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(size, type, stride,
+                            process->current_state->texCoordPointer[0]);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexAndNormalPointer_fake_func:
+        {
+            int vertexPointer_size = args[0];
+            int vertexPointer_type = args[1];
+            int vertexPointer_stride = args[2];
+            int normalPointer_type = args[3];
+            int normalPointer_stride = args[4];
+            int bytes_size = args[5];
+            const void *ptr = (const void *) args[6];
+
+            process->current_state->vertexPointer_size = bytes_size;
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer, bytes_size);
+            memcpy(process->current_state->vertexPointer, ptr, bytes_size);
+            glVertexPointer(vertexPointer_size, vertexPointer_type,
+                            vertexPointer_stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, normalPointer_stride,
+                            process->current_state->vertexPointer);
+            break;
+        }
+
+    case glVertexNormalPointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            break;
+        }
+
+    case glTuxRacerDrawElements_fake_func:
+        /* Optimised version of glDrawElements selected by the guest
+         * agent when appropriate.  */
+        {
+            int mode = args[0];
+            int count = args[1];
+            int is_color_enabled = args[2];
+            const void *ptr = (const void *) args[3];
+            int stride = 6 * sizeof(GLfloat) +
+                (is_color_enabled ? 4 * sizeof(GLubyte) : 0);
+            glVertexPointer(3, GL_FLOAT, stride, ptr);
+            glNormalPointer(GL_FLOAT, stride, ptr + 3 * sizeof(GLfloat));
+            if (is_color_enabled) {
+                glColorPointer(4, GL_UNSIGNED_BYTE, stride,
+                                ptr + 6 * sizeof(GLfloat));
+            }
+            check_arrays(process, count - 1, 1);
+            glDrawArrays(mode, 0, count);
+            break;
+        }
+
+    case glVertexNormalColorPointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int colorPointer_offset = args[i++];
+            int colorPointer_size = args[i++];
+            int colorPointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            glColorPointer(colorPointer_size, colorPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            colorPointer_offset);
+            break;
+        }
+
+    case glVertexColorTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int colorPointer_offset = args[i++];
+            int colorPointer_size = args[i++];
+            int colorPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glColorPointer(colorPointer_size, colorPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            colorPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalTexCoord01PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int texCoord1Pointer_offset = args[i++];
+            int texCoord1Pointer_size = args[i++];
+            int texCoord1Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1Pointer_size, texCoord1Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord1Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalTexCoord012PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int texCoord1Pointer_offset = args[i++];
+            int texCoord1Pointer_size = args[i++];
+            int texCoord1Pointer_type = args[i++];
+            int texCoord2Pointer_offset = args[i++];
+            int texCoord2Pointer_size = args[i++];
+            int texCoord2Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1Pointer_size, texCoord1Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord1Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(texCoord2Pointer_size, texCoord2Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord2Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord0PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int colorPointer_offset = args[i++];
+            int colorPointer_size = args[i++];
+            int colorPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            glColorPointer(colorPointer_size, colorPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            colorPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord01PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int colorPointer_offset = args[i++];
+            int colorPointer_size = args[i++];
+            int colorPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int texCoord1Pointer_offset = args[i++];
+            int texCoord1Pointer_size = args[i++];
+            int texCoord1Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            glColorPointer(colorPointer_size, colorPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            colorPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1Pointer_size, texCoord1Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord1Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case glVertexNormalColorTexCoord012PointerInterlaced_fake_func:
+        {
+            int i = 0;
+            int offset = args[i++];
+            int vertexPointer_size = args[i++];
+            int vertexPointer_type = args[i++];
+            int stride = args[i++];
+            int normalPointer_offset = args[i++];
+            int normalPointer_type = args[i++];
+            int colorPointer_offset = args[i++];
+            int colorPointer_size = args[i++];
+            int colorPointer_type = args[i++];
+            int texCoord0Pointer_offset = args[i++];
+            int texCoord0Pointer_size = args[i++];
+            int texCoord0Pointer_type = args[i++];
+            int texCoord1Pointer_offset = args[i++];
+            int texCoord1Pointer_size = args[i++];
+            int texCoord1Pointer_type = args[i++];
+            int texCoord2Pointer_offset = args[i++];
+            int texCoord2Pointer_size = args[i++];
+            int texCoord2Pointer_type = args[i++];
+            int bytes_size = args[i++];
+            const void *ptr = (const void *) args[i++];
+
+            process->current_state->vertexPointer_size =
+                MAX(process->current_state->vertexPointer_size,
+                                offset + bytes_size);
+            process->current_state->vertexPointer =
+                g_realloc(process->current_state->vertexPointer,
+                                process->current_state->vertexPointer_size);
+            memcpy(process->current_state->vertexPointer + offset, ptr,
+                            bytes_size);
+
+            glVertexPointer(vertexPointer_size, vertexPointer_type, stride,
+                            process->current_state->vertexPointer);
+            glNormalPointer(normalPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            normalPointer_offset);
+            glColorPointer(colorPointer_size, colorPointer_type, stride,
+                            process->current_state->vertexPointer +
+                            colorPointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 0);
+            glTexCoordPointer(texCoord0Pointer_size, texCoord0Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord0Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 1);
+            glTexCoordPointer(texCoord1Pointer_size, texCoord1Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord1Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB + 2);
+            glTexCoordPointer(texCoord2Pointer_size, texCoord2Pointer_type,
+                            stride, process->current_state->vertexPointer +
+                            texCoord2Pointer_offset);
+            do_glClientActiveTextureARB(GL_TEXTURE0_ARB +
+                            process->current_state->active_texture_idx);
+            break;
+        }
+
+    case vmglVertexPointer_buffer_func:
+        glVertexPointer(args[0], args[1], args[2], (void *) args[3]);
+        break;
+
+    case vmglNormalPointer_buffer_func:
+        glNormalPointer(args[0], args[1], (void *) args[2]);
+        break;
+
+    case vmglColorPointer_buffer_func:
+        glColorPointer(args[0], args[1], args[2], (void *) args[3]);
+        break;
+
+    case vmglSecondaryColorPointer_buffer_func:
+        {
+            GET_EXT_PTR(void, glSecondaryColorPointer,
+                            (int, int, int, void *));
+            ptr_func_glSecondaryColorPointer(args[0], args[1], args[2],
+                            (void *) args[3]);
+            break;
+        }
+
+    case vmglIndexPointer_buffer_func:
+        glIndexPointer(args[0], args[1], (void *) args[2]);
+        break;
+
+    case vmglTexCoordPointer_buffer_func:
+        glTexCoordPointer(args[0], args[1], args[2], (void *) args[3]);
+        break;
+
+    case vmglEdgeFlagPointer_buffer_func:
+        glEdgeFlagPointer(args[0], (void *) args[1]);
+        break;
+
+    case vmglVertexAttribPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glVertexAttribPointerARB,
+                            (int, int, int, int, int, void *));
+
+            ptr_func_glVertexAttribPointerARB(args[0], args[1], args[2],
+                            args[3], args[4], (void *) args[5]);
+            break;
+        }
+
+    case vmglWeightPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glWeightPointerARB, (int, int, int, void *));
+
+            ptr_func_glWeightPointerARB(args[0], args[1], args[2],
+                            (void *) args[3]);
+            break;
+        }
+
+    case vmglMatrixIndexPointerARB_buffer_func:
+        {
+            GET_EXT_PTR(void, glMatrixIndexPointerARB,
+                            (int, int, int, void *));
+
+            ptr_func_glMatrixIndexPointerARB(args[0], args[1], args[2],
+                            (void *) args[3]);
+            break;
+        }
+
+    case vmglFogCoordPointer_buffer_func:
+        {
+            GET_EXT_PTR(void, glFogCoordPointer, (int, int, void *));
+
+            ptr_func_glFogCoordPointer(args[0], args[1], (void *) args[2]);
+            break;
+        }
+
+    case vmglVariantPointerEXT_buffer_func:
+        {
+            GET_EXT_PTR(void, glVariantPointerEXT, (int, int, int, void *));
+
+            ptr_func_glVariantPointerEXT(args[0], args[1], args[2],
+                            (void *) args[3]);
+            break;
+        }
+
+    case glArrayElement_func:
+        /* TODO: check on the host that EBO is actually enabled */
+        /* TODO: check if there's any benefit of using
+         * _glElementArrayImmediate() on the guest.  */
+        {
+            GET_EXT_PTR(void, glArrayElement, (GLint));
+
+            int i = args[0];
+
+            /* glArrayElements is used between glBegin/glEnd, so we can't
+             * just glDisableVertexAttribArray in case of insufficient
+             * data in the array.  We need to bail out.  */
+            if (check_arrays(process, i, 0)) {
+                return 0;
+            }
+
+            ptr_func_glArrayElement(args[0]);
+
+            break;
+        }
+
+    case vmglDrawElements_buffer_func:
+        /* TODO: check on the host that EBO is actually enabled */
+        glDrawElements(args[0], args[1], args[2], (void *) args[3]);
+        break;
+
+    case glDrawElements_func:
+        {
+            int i, idx, max = 0;
+            int count = args[1], size = args[1];
+            uint8_t *indices = (void *) args[3];
+            int type = args[2];
+
+            switch (type) {
+            case GL_UNSIGNED_BYTE:
+                break;
+            case GL_UNSIGNED_SHORT:
+                size *= 2;
+                break;
+            case GL_UNSIGNED_INT:
+                size *= 4;
+                break;
+            default:
+                return 0;
+            }
+            if (size > process->current_state->own_indices_size) {
+                process->current_state->own_indices =
+                    g_realloc(process->current_state->own_indices, size);
+                process->current_state->own_indices_size = size;
+            }
+
+            for (i = 0; i < count; i++) {
+                switch (type) {
+                case GL_UNSIGNED_BYTE:
+                    idx = indices[i];
+                    process->current_state->own_indices[i] = idx;
+                    break;
+                case GL_UNSIGNED_SHORT:
+                    idx = uint16_to_cpu(((uint16_t *) indices)[i]);
+                    ((uint16_t *) process->current_state->own_indices)[i] = idx;
+                    break;
+                case GL_UNSIGNED_INT:
+                    idx = uint32_to_cpu(((uint32_t *) indices)[i]);
+                    ((uint32_t *) process->current_state->own_indices)[i] = idx;
+                    break;
+                default:
+                    return 0;
+                }
+
+                if (idx > max) {
+                    max = idx;
+                }
+            }
+
+            check_arrays(process, max, 1);
+            glDrawElements(args[0], count, type,
+                            process->current_state->own_indices);
+            break;
+        }
+
+    case glDrawArrays_func:
+        {
+            int mode = args[0];
+            int first = args[1];
+            int count = args[2];
+
+            check_arrays(process, first + count - 1, 1);
+            glDrawArrays(mode, first, count);
+            break;
+        }
+
+#ifndef _WIN32
+    case vmglDrawRangeElements_buffer_func:
+        /* TODO: check on the host that EBO is actually enabled */
+        glDrawRangeElements(args[0], args[1], args[2], args[3], args[4],
+                        (void *) args[5]);
+        break;
+
+    case glDrawRangeElements_func:
+        {
+            int i, idx, max = 0;
+            int count = args[3], size = args[3];
+            uint8_t *indices = (void *) args[5];
+            int type = args[4];
+
+            switch (type) {
+            case GL_UNSIGNED_BYTE:
+                break;
+            case GL_UNSIGNED_SHORT:
+                size *= 2;
+                break;
+            case GL_UNSIGNED_INT:
+                size *= 4;
+                break;
+            default:
+                return 0;
+            }
+            if (size > process->current_state->own_indices_size) {
+                process->current_state->own_indices =
+                    g_realloc(process->current_state->own_indices, size);
+                process->current_state->own_indices_size = size;
+            }
+
+            for (i = 0; i < count; i++) {
+                switch (type) {
+                case GL_UNSIGNED_BYTE:
+                    idx = indices[i];
+                    process->current_state->own_indices[i] = idx;
+                    break;
+                case GL_UNSIGNED_SHORT:
+                    idx = uint16_to_cpu(((uint16_t *) indices)[i]);
+                    ((uint16_t *) process->current_state->own_indices)[i] = idx;
+                    break;
+                case GL_UNSIGNED_INT:
+                    idx = uint32_to_cpu(((uint32_t *) indices)[i]);
+                    ((uint32_t *) process->current_state->own_indices)[i] = idx;
+                    break;
+                default:
+                    return 0;
+                }
+
+                if (idx > max) {
+                    max = idx;
+                }
+            }
+
+            check_arrays(process, max, 1);
+            glDrawRangeElements(args[0], args[1], args[2], count, type,
+                            process->current_state->own_indices);
+        }
+
+        break;
+#endif
+
+    case vmglMultiDrawElements_buffer_func:
+        /* TODO: reimplement in libgl to call vmglDrawElements_buffer
+         * multiple times */
+
+        {
+            GET_EXT_PTR(void, glMultiDrawElements,
+                            (int, GLuint *, int, void **, int));
+
+            ptr_func_glMultiDrawElements(args[0], (uint32_t *) args[1], args[2],
+                            (void **) args[3], args[4]);
+            break;
+        }
+
+    case vmglGetError_fake_func:
+        break;
+
+    case glGetIntegerv_func:
+        glGetIntegerv(args[0], (int32_t *) args[1]);
+        break;
+
+    case vmglReadPixels_pbo_func:
+        glReadPixels(ARG_TO_INT(args[0]), ARG_TO_INT(args[1]),
+                        ARG_TO_INT(args[2]), ARG_TO_INT(args[3]),
+                        ARG_TO_UNSIGNED_INT(args[4]),
+                        ARG_TO_UNSIGNED_INT(args[5]), (void *) (args[6]));
+        break;
+
+    case vmglDrawPixels_pbo_func:
+        glDrawPixels(ARG_TO_INT(args[0]), ARG_TO_INT(args[1]),
+                        ARG_TO_UNSIGNED_INT(args[2]),
+                        ARG_TO_UNSIGNED_INT(args[3]),
+                        (const void *) (args[4]));
+        break;
+
+    case vmglMapBufferARB_fake_func:
+        {
+            GET_EXT_PTR(GLvoid *, glMapBufferARB, (GLenum, GLenum));
+            GET_EXT_PTR(GLboolean, glUnmapBufferARB, (GLenum));
+            int target = args[0];
+            int size = args[1];
+            void *dst_ptr = (void *) args[2];
+            const void *src_ptr = ptr_func_glMapBufferARB(target, GL_READ_ONLY);
+
+            if (src_ptr) {
+                memcpy(dst_ptr, src_ptr, size);
+                ret.i = ptr_func_glUnmapBufferARB(target);
+            } else {
+                ret.i = 0;
+            }
+            break;
+        }
+
+    case fake_gluBuild2DMipmaps_func:
+        {
+            GET_GLU_PTR(GLint, gluBuild2DMipmaps,
+                            (GLenum arg_0, GLint arg_1, GLsizei arg_2,
+                             GLsizei arg_3, GLenum arg_4, GLenum arg_5,
+                             const GLvoid *arg_6));
+
+            if (ptr_func_gluBuild2DMipmaps == NULL) {
+                ptr_func_gluBuild2DMipmaps = mesa_gluBuild2DMipmaps;
+            }
+            ptr_func_gluBuild2DMipmaps(ARG_TO_UNSIGNED_INT(args[0]),
+                            ARG_TO_INT(args[1]), ARG_TO_INT(args[2]),
+                            ARG_TO_INT(args[3]), ARG_TO_UNSIGNED_INT(args[4]),
+                            ARG_TO_UNSIGNED_INT(args[5]),
+                            (const void *) (args[6]));
+            break;
+        }
+
+    case vmglSelectBuffer_fake_func:
+        process->current_state->selectBuffer_size = args[0] * 4;
+        process->current_state->selectBuffer_ptr =
+            g_realloc(process->current_state->selectBuffer_ptr,
+                            process->current_state->selectBuffer_size);
+
+        glSelectBuffer(args[0], process->current_state->selectBuffer_ptr);
+        break;
+
+    case vmglGetSelectBuffer_fake_func:
+        {
+            void *ptr = (void *) args[0];
+
+            memcpy(ptr, process->current_state->selectBuffer_ptr,
+                            process->current_state->selectBuffer_size);
+            break;
+        }
+
+    case vmglFeedbackBuffer_fake_func:
+        process->current_state->feedbackBuffer_size = args[0] * 4;
+        process->current_state->feedbackBuffer_ptr =
+            g_realloc(process->current_state->feedbackBuffer_ptr,
+                            process->current_state->feedbackBuffer_size);
+        glFeedbackBuffer((GLsizei)args[0], (GLenum) args[1],
+                        process->current_state->feedbackBuffer_ptr);
+        break;
+
+    case vmglGetFeedbackBuffer_fake_func:
+        {
+            void *ptr = (void *) args[0];
+
+            memcpy(ptr, process->current_state->feedbackBuffer_ptr,
+                            process->current_state->feedbackBuffer_size);
+            break;
+        }
+
+    case glLockArraysEXT_func:
+    case glUnlockArraysEXT_func:
+        break;
+
+    default:
+        execute_func(func_number, args, &ret);
+        break;
+    }
+
+    switch (ret_type) {
+    case TYPE_CHAR:
+    case TYPE_UNSIGNED_CHAR:
+        *ret_buffer = ret.i & 0xff;
+        break;
+    case TYPE_INT:
+    case TYPE_UNSIGNED_INT:
+        memcpy(ret_buffer, &ret.i, 4);
+        break;
+    case TYPE_NONE:
+        break;
+    case TYPE_CONST_CHAR:
+        strncpy((char *) ret_buffer, ret.s ? ret.s : "", 32768);
+        break;
+
+    default:
+        DEBUGF("Unsupported GL API return type: %i\n", ret_type);
+        exit(-1);
+        break;
+    }
+
+    if (display_function_call) {
+        DEBUGF("[%d]< %s\n", process->p.process_id,
+                        tab_opengl_calls_name[func_number]);
+    }
+
+    return 1;
+}
+
+/* do_decode_call_int()
+ *
+ * Loop through the buffered command stream executing each OpenGL call in
+ * sequence.  Due to the way calls are buffered, only the last call in the
+ * buffer may have 'out' parameters or a non-void return code. This allows
+ * for efficient buffering whilst avoiding unnecessary buffer flushes.
+ */
+
+static inline int do_decode_call(ProcessStruct *p, const uint8_t *args_in,
+                int args_len, uint8_t *r_buffer)
+{
+    Signature *signature;
+    int i;
+    const uint8_t *arg_ptr;
+    static arg_t args[50];
+    int func_number;
+    ProcessState *process = DO_UPCAST(ProcessState, p, p);
+
+    if (!args_len) {
+        return 0;
+    }
+
+    arg_ptr = args_in;
+
+    while (arg_ptr < args_in + args_len) {
+        func_number = uint16_to_cpu(*(const uint16_t *) arg_ptr);
+        arg_ptr += 2;
+
+        if (func_number >= GL_N_CALLS) {
+            DEBUGF("Bad function number or corrupt command queue\n");
+            return 0;
+        }
+
+#ifdef DIFFERING_ENDIANNESS
+        DEBUGF("FIXME: guests of differing endianness not supported\n");
+        return 0;
+#endif
+
+        signature = (Signature *) tab_opengl_calls[func_number];
+
+        for (i = 0; i < signature->nb_args; i++) {
+            int args_size = *(const uint32_t *) arg_ptr;
+
+            arg_ptr += 4;
+            switch (signature->args_type[i]) {
+            case TYPE_UNSIGNED_INT:
+            case TYPE_INT:
+            case TYPE_UNSIGNED_CHAR:
+            case TYPE_CHAR:
+            case TYPE_UNSIGNED_SHORT:
+            case TYPE_SHORT:
+            case TYPE_FLOAT:
+                args[i] = *(const uint32_t *) arg_ptr;
+                break;
+
+            case TYPE_NULL_TERMINATED_STRING:
+            CASE_IN_UNKNOWN_SIZE_POINTERS:
+            {
+                if (*(const uint32_t *) arg_ptr) {
+                    args[i] = PTR_TO_ARG(arg_ptr + 4);
+                } else {
+                    args[i] = PTR_TO_ARG(NULL);
+                }
+
+                if ((args[i] == 0 && args_size == 0 &&
+                        !IS_NULL_POINTER_OK_FOR_FUNC(func_number)) ||
+                        (args[i] == 0 && args_size != 0) ||
+                        (args[i] != 0 && args_size == 0)) {
+                    return 0;
+                }
+
+                arg_ptr += 4;
+                break;
+            }
+
+            CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS:
+            {
+                if (*(const uint32_t *) arg_ptr) {
+                    args[i] = PTR_TO_ARG(arg_ptr + 4);
+                } else {
+                    args[i] = PTR_TO_ARG(NULL);
+                }
+
+                if (args[i] == 0 && args_size != 0) {
+                    return 0;
+                }
+
+                arg_ptr += 4;
+                break;
+            }
+
+            CASE_OUT_POINTERS:
+            {
+                /* It seems that NULL out pointers are needed */
+                if (args_size == 0 && func_number != glXChooseVisual_func) {
+                    return 0;
+                }
+
+                if (*(const uint32_t *) arg_ptr) {
+                    *(uint32_t *) r_buffer = args_size;
+                    r_buffer += 4;
+                    args[i] = PTR_TO_ARG(r_buffer);
+                    r_buffer += args_size;
+                } else {
+                    args[i] = 0;
+                }
+
+                arg_ptr += 4;
+                args_size = 0;
+                break;
+            }
+
+            case TYPE_DOUBLE:
+            CASE_IN_KNOWN_SIZE_POINTERS:
+            {
+                if (*(const uint32_t *) arg_ptr) {
+                    args[i] = PTR_TO_ARG(arg_ptr + 4);
+                } else {
+                    args[i] = PTR_TO_ARG(NULL);
+                }
+
+                if (args[i] == 0 && args_size != 0) {
+                    return 0;
+                }
+
+                arg_ptr += 4;
+                break;
+            }
+
+            case TYPE_IN_IGNORED_POINTER:
+                args[i] = 0;
+                break;
+
+            default:
+                DEBUGF("Oops: call %s arg %d pid=%d\n",
+                                tab_opengl_calls_name[func_number], i,
+                                process->p.process_id);
+                return 0;
+            }
+            arg_ptr += args_size;
+        }
+
+        if (arg_ptr > args_in + args_len) {
+            DEBUGF("Client bug: malformed command, killing process\n");
+            return 0;
+        }
+
+        if (!do_function_call(process, func_number, args, r_buffer)) {
+            return 0;
+        }
+    }
+
+#ifdef DIFFERING_ENDIANNESS
+    switch (signature->ret_type) {
+    case TYPE_INT:
+    case TYPE_UNSIGNED_INT:
+        ((uint32_t *) r_buffer)[0] = cpu_to_uint32(((uint32_t *) r_buffer)[0]);
+        break;
+    }
+#endif
+
+    return 1;
+}
+
+#define GL_PASSTHROUGH_ABI 1
+
+enum {
+    GLINIT_NOQUEUE = 1,
+    GLINIT_QUEUE = 2,
+    GLINIT_FAIL_ABI = 3,
+};
+
+int vmgl_decode_call(ProcessStruct *process, const uint8_t *in_args,
+                int args_len, uint8_t *r_buffer)
+{
+    static ProcessStruct *cur_process;
+    int ret;
+    int first_func = uint16_to_cpu(*(const uint16_t *) in_args);
+
+    /* Select the appropriate context for this pid if it isnt already active
+     * Note: if we're about to execute glXMakeCurrent() then we tell the
+     * renderer not to waste its time switching contexts
+     */
+
+    if (cur_process != process) {
+        cur_process = process;
+        vmgl_context_switch(cur_process, first_func != glXMakeCurrent_func);
+    }
+
+    if (unlikely(first_func == vmgl_init32_func ||
+            first_func == vmgl_init64_func)) {
+        if (!cur_process->wordsize) {
+            const uint32_t *version = (const uint32_t *) (in_args + 2);
+            cur_process->wordsize = first_func == vmgl_init32_func ? 4 : 8;
+
+            if (uint32_to_cpu(version[0]) != 1 ||
+                    uint32_to_cpu(version[1]) < GL_PASSTHROUGH_ABI) {
+                *(uint32_t *) r_buffer = cpu_to_uint32(GLINIT_FAIL_ABI);
+                fprintf(stderr, "vmgl error: The GL passthrough package in the "
+                                "image does not match the version of QEMUGL.  "
+                                "Please update the image.\n");
+                return 0;
+            } else if (version[1] > GL_PASSTHROUGH_ABI) {
+                *(uint32_t *) r_buffer = cpu_to_uint32(GLINIT_FAIL_ABI);
+                fprintf(stderr, "vmgl error: The GL passthrough package in the "
+                                "image does not match the version of QEMUGL.  "
+                                "Please update QEMU.\n");
+                return 0;
+            } else {
+                /* Indicate that we can buffer commands */
+                *(uint32_t *) r_buffer = cpu_to_uint32(GLINIT_QUEUE);
+            }
+
+            return 1; /* Initialisation done */
+        } else {
+            DEBUGF("Attempt to init twice.  Continuing regardless.\n");
+            return 1;
+        }
+    } else if (unlikely(first_func == -1 || !cur_process->wordsize)) {
+        if (!cur_process->wordsize && first_func != -1) {
+            DEBUGF("commands submitted before process init.\n");
+        }
+        cur_process = NULL;
+        return 0;
+    }
+
+    ret = do_decode_call(cur_process, in_args, args_len, r_buffer);
+
+    if (!ret) {
+        cur_process = NULL;
+    }
+
+    return ret;
+}
+
+int vmgl_acceleration_capability_check(void)
+{
+    return glo_acceleration_capability_check();
+}
diff --git a/gl/vmgl-func-perso.h b/gl/vmgl-func-perso.h
new file mode 100644
index 0000000..a35e871
--- /dev/null
+++ b/gl/vmgl-func-perso.h
@@ -0,0 +1,120 @@
+/*
+ * GLX and other non-GL functions.
+ *
+ * Copyright (c) 2006,2007 Even Rouault
+ * Copyright (c) 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+MAGIC_MACRO(vmgl_init32),
+MAGIC_MACRO(vmgl_init64),
+MAGIC_MACRO(vmgl_resize_surface),
+MAGIC_MACRO(vmgl_render_surface),
+
+/* When you add a glX call here, you HAVE TO update IS_GLX_CALL */
+MAGIC_MACRO(glXChooseVisual),
+MAGIC_MACRO(glXQueryExtensionsString),
+MAGIC_MACRO(glXQueryServerString),
+MAGIC_MACRO(glXCreateContext),
+MAGIC_MACRO(glXCopyContext),
+MAGIC_MACRO(glXDestroyContext),
+MAGIC_MACRO(glXGetClientString),
+MAGIC_MACRO(glXQueryVersion),
+MAGIC_MACRO(glXMakeCurrent),
+MAGIC_MACRO(glXGetConfig),
+MAGIC_MACRO(glXGetConfig_extended),
+MAGIC_MACRO(glXWaitGL),
+MAGIC_MACRO(glXWaitX),
+MAGIC_MACRO(glXGetFBConfigAttrib_extended),
+MAGIC_MACRO(glXChooseFBConfig),
+MAGIC_MACRO(glXGetFBConfigs),
+MAGIC_MACRO(glXCreateNewContext),
+MAGIC_MACRO(glXGetVisualFromFBConfig),
+MAGIC_MACRO(glXGetFBConfigAttrib),
+MAGIC_MACRO(glXQueryContext),
+MAGIC_MACRO(glXQueryDrawable),
+MAGIC_MACRO(glXUseXFont),
+MAGIC_MACRO(glXIsDirect),
+MAGIC_MACRO(glXGetProcAddress_fake),
+MAGIC_MACRO(glXGetProcAddress_global_fake),
+MAGIC_MACRO(glXSwapBuffers),
+MAGIC_MACRO(glXQueryExtension),
+MAGIC_MACRO(glXGetScreenDriver),
+MAGIC_MACRO(glXGetDriverConfig),
+MAGIC_MACRO(glXSwapIntervalSGI),
+
+MAGIC_MACRO(glGetString),
+
+MAGIC_MACRO(glShaderSourceARB_fake),
+MAGIC_MACRO(glShaderSource_fake),
+MAGIC_MACRO(glVertexPointer_fake),
+MAGIC_MACRO(glNormalPointer_fake),
+MAGIC_MACRO(glColorPointer_fake),
+MAGIC_MACRO(glSecondaryColorPointer_fake),
+MAGIC_MACRO(glIndexPointer_fake),
+MAGIC_MACRO(glTexCoordPointer_fake),
+MAGIC_MACRO(glEdgeFlagPointer_fake),
+MAGIC_MACRO(glVertexAttribPointerARB_fake),
+MAGIC_MACRO(glVertexAttribPointerNV_fake),
+MAGIC_MACRO(glWeightPointerARB_fake),
+MAGIC_MACRO(glMatrixIndexPointerARB_fake),
+MAGIC_MACRO(glFogCoordPointer_fake),
+MAGIC_MACRO(glVariantPointerEXT_fake),
+MAGIC_MACRO(glInterleavedArrays_fake),
+MAGIC_MACRO(glElementPointerATI_fake),
+MAGIC_MACRO(glTuxRacerDrawElements_fake),
+MAGIC_MACRO(glVertexAndNormalPointer_fake),
+MAGIC_MACRO(glTexCoordPointer01_fake),
+MAGIC_MACRO(glTexCoordPointer012_fake),
+MAGIC_MACRO(glVertexNormalPointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorPointerInterlaced_fake),
+MAGIC_MACRO(glVertexColorTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord01PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalTexCoord012PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord0PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord01PointerInterlaced_fake),
+MAGIC_MACRO(glVertexNormalColorTexCoord012PointerInterlaced_fake),
+MAGIC_MACRO(glGenTextures_fake),
+MAGIC_MACRO(glGenBuffersARB_fake),
+MAGIC_MACRO(glGenLists_fake),
+MAGIC_MACRO(vmglDrawElements_buffer),
+MAGIC_MACRO(vmglDrawRangeElements_buffer),
+MAGIC_MACRO(vmglMultiDrawElements_buffer),
+MAGIC_MACRO(vmglVertexPointer_buffer),
+MAGIC_MACRO(vmglNormalPointer_buffer),
+MAGIC_MACRO(vmglColorPointer_buffer),
+MAGIC_MACRO(vmglSecondaryColorPointer_buffer),
+MAGIC_MACRO(vmglIndexPointer_buffer),
+MAGIC_MACRO(vmglTexCoordPointer_buffer),
+MAGIC_MACRO(vmglEdgeFlagPointer_buffer),
+MAGIC_MACRO(vmglVertexAttribPointerARB_buffer),
+MAGIC_MACRO(vmglWeightPointerARB_buffer),
+MAGIC_MACRO(vmglMatrixIndexPointerARB_buffer),
+MAGIC_MACRO(vmglFogCoordPointer_buffer),
+MAGIC_MACRO(vmglVariantPointerEXT_buffer),
+MAGIC_MACRO(vmglGetError_fake),
+MAGIC_MACRO(vmglReadPixels_pbo),
+MAGIC_MACRO(vmglDrawPixels_pbo),
+MAGIC_MACRO(vmglMapBufferARB_fake),
+MAGIC_MACRO(vmglSelectBuffer_fake),
+MAGIC_MACRO(vmglGetSelectBuffer_fake),
+MAGIC_MACRO(vmglFeedbackBuffer_fake),
+MAGIC_MACRO(vmglGetFeedbackBuffer_fake),
diff --git a/gl/vmgl-func.h b/gl/vmgl-func.h
new file mode 100644
index 0000000..187033c
--- /dev/null
+++ b/gl/vmgl-func.h
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2006,2007 Even Rouault
+ *
+ * Parts written by:
+ *   Gordon Williams <gordon.williams@collabora.co.uk>
+ *   Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef OPENGL_FUNC_H
+#define OPENGL_FUNC_H
+
+#include "mesa_gl.h"
+#include "mesa_glext.h"
+
+#include "targphys.h"
+
+enum {
+    TYPE_NONE,
+    TYPE_CHAR,
+    TYPE_UNSIGNED_CHAR,
+    TYPE_SHORT,
+    TYPE_UNSIGNED_SHORT,
+    TYPE_INT,
+    TYPE_UNSIGNED_INT,
+    TYPE_FLOAT,
+    TYPE_DOUBLE,
+    TYPE_1CHAR,
+    TYPE_2CHAR,
+    TYPE_3CHAR,
+    TYPE_4CHAR,
+    TYPE_128UCHAR,
+    TYPE_1SHORT,
+    TYPE_2SHORT,
+    TYPE_3SHORT,
+    TYPE_4SHORT,
+    TYPE_1INT,
+    TYPE_2INT,
+    TYPE_3INT,
+    TYPE_4INT,
+    TYPE_1FLOAT,
+    TYPE_2FLOAT,
+    TYPE_3FLOAT,
+    TYPE_4FLOAT,
+    TYPE_16FLOAT,
+    TYPE_1DOUBLE,
+    TYPE_2DOUBLE,
+    TYPE_3DOUBLE,
+    TYPE_4DOUBLE,
+    TYPE_16DOUBLE,
+    TYPE_OUT_1INT,
+    TYPE_OUT_1FLOAT,
+    TYPE_OUT_4CHAR,
+    TYPE_OUT_4INT,
+    TYPE_OUT_4FLOAT,
+    TYPE_OUT_4DOUBLE,
+    TYPE_OUT_128UCHAR,
+    TYPE_CONST_CHAR,
+    TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_SHORT,
+    TYPE_ARRAY_INT,
+    TYPE_ARRAY_FLOAT,
+    TYPE_ARRAY_DOUBLE,
+    TYPE_IN_IGNORED_POINTER,
+    TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_SHORT,
+    TYPE_OUT_ARRAY_INT,
+    TYPE_OUT_ARRAY_FLOAT,
+    TYPE_OUT_ARRAY_DOUBLE,
+    TYPE_NULL_TERMINATED_STRING,
+
+    TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    /* .... */
+    TYPE_LAST,
+    /* .... */
+    TYPE_1UCHAR = TYPE_CHAR,
+    TYPE_1USHORT = TYPE_1SHORT,
+    TYPE_1UINT = TYPE_1INT,
+    TYPE_OUT_1UINT = TYPE_OUT_1INT,
+    TYPE_OUT_4UCHAR = TYPE_OUT_4CHAR,
+    TYPE_ARRAY_VOID = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_SIGNED_CHAR = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_UNSIGNED_CHAR = TYPE_ARRAY_CHAR,
+    TYPE_ARRAY_UNSIGNED_SHORT = TYPE_ARRAY_SHORT,
+    TYPE_ARRAY_UNSIGNED_INT = TYPE_ARRAY_INT,
+    TYPE_OUT_ARRAY_VOID = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_SIGNED_CHAR = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_UNSIGNED_CHAR = TYPE_OUT_ARRAY_CHAR,
+    TYPE_OUT_ARRAY_UNSIGNED_SHORT = TYPE_OUT_ARRAY_SHORT,
+    TYPE_OUT_ARRAY_UNSIGNED_INT = TYPE_OUT_ARRAY_INT,
+    TYPE_ARRAY_VOID_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_SIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_ARRAY_UNSIGNED_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_VOID_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_SIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+    TYPE_OUT_ARRAY_UNSIGNED_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS =
+        TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS,
+};
+
+#define CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS \
+    case TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_OUT_LENGTH_DEPENDING_ON_PREVIOUS_ARGS \
+    case TYPE_OUT_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_OUT_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_OUT_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_OUT_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS: \
+    case TYPE_OUT_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_IN_UNKNOWN_SIZE_POINTERS \
+    case TYPE_ARRAY_CHAR: \
+    case TYPE_ARRAY_SHORT: \
+    case TYPE_ARRAY_INT: \
+    case TYPE_ARRAY_FLOAT: \
+    case TYPE_ARRAY_DOUBLE
+
+#define CASE_IN_KNOWN_SIZE_POINTERS \
+    case TYPE_1CHAR:\
+    case TYPE_2CHAR:\
+    case TYPE_3CHAR:\
+    case TYPE_4CHAR:\
+    case TYPE_128UCHAR:\
+    case TYPE_1SHORT:\
+    case TYPE_2SHORT:\
+    case TYPE_3SHORT:\
+    case TYPE_4SHORT:\
+    case TYPE_1INT:\
+    case TYPE_2INT:\
+    case TYPE_3INT:\
+    case TYPE_4INT:\
+    case TYPE_1FLOAT:\
+    case TYPE_2FLOAT:\
+    case TYPE_3FLOAT:\
+    case TYPE_4FLOAT:\
+    case TYPE_16FLOAT:\
+    case TYPE_1DOUBLE:\
+    case TYPE_2DOUBLE:\
+    case TYPE_3DOUBLE:\
+    case TYPE_4DOUBLE:\
+    case TYPE_16DOUBLE
+
+#define CASE_OUT_UNKNOWN_SIZE_POINTERS \
+    case TYPE_OUT_ARRAY_CHAR: \
+    case TYPE_OUT_ARRAY_SHORT: \
+    case TYPE_OUT_ARRAY_INT: \
+    case TYPE_OUT_ARRAY_FLOAT: \
+    case TYPE_OUT_ARRAY_DOUBLE
+
+#define CASE_OUT_KNOWN_SIZE_POINTERS \
+    case TYPE_OUT_1INT: \
+    case TYPE_OUT_1FLOAT: \
+    case TYPE_OUT_4CHAR: \
+    case TYPE_OUT_4INT: \
+    case TYPE_OUT_4FLOAT: \
+    case TYPE_OUT_4DOUBLE: \
+    case TYPE_OUT_128UCHAR \
+
+#define CASE_IN_POINTERS \
+    CASE_IN_UNKNOWN_SIZE_POINTERS: \
+    CASE_IN_KNOWN_SIZE_POINTERS: \
+    CASE_IN_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+#define CASE_OUT_POINTERS \
+    CASE_OUT_UNKNOWN_SIZE_POINTERS: \
+    CASE_OUT_KNOWN_SIZE_POINTERS: \
+    CASE_OUT_LENGTH_DEPENDING_ON_PREVIOUS_ARGS
+
+#define CASE_POINTERS \
+    CASE_IN_POINTERS: \
+    CASE_OUT_POINTERS
+#define CASE_KNOWN_SIZE_POINTERS \
+    CASE_IN_KNOWN_SIZE_POINTERS: \
+    CASE_OUT_KNOWN_SIZE_POINTERS
+
+#define IS_ARRAY_CHAR(type) \
+    (type == TYPE_ARRAY_CHAR || type == TYPE_1CHAR || type == TYPE_2CHAR || \
+     type == TYPE_3CHAR || type == TYPE_4CHAR || \
+     type == TYPE_ARRAY_CHAR_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_SHORT(type) \
+    (type == TYPE_ARRAY_SHORT || type == TYPE_1SHORT || type == TYPE_2SHORT || \
+     type == TYPE_3SHORT || type == TYPE_4SHORT || \
+     type == TYPE_ARRAY_SHORT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_INT(type) \
+    (type == TYPE_ARRAY_INT || type == TYPE_1INT || type == TYPE_2INT || \
+     type == TYPE_3INT || type == TYPE_4INT || \
+     type == TYPE_ARRAY_INT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_FLOAT(type) \
+    (type == TYPE_ARRAY_FLOAT || type == TYPE_1FLOAT || type == TYPE_2FLOAT || \
+     type == TYPE_3FLOAT || type == TYPE_4FLOAT || type == TYPE_16FLOAT || \
+     type == TYPE_ARRAY_FLOAT_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+#define IS_ARRAY_DOUBLE(type) \
+    (type == TYPE_ARRAY_DOUBLE || type == TYPE_1DOUBLE || \
+     type == TYPE_2DOUBLE || type == TYPE_3DOUBLE || type == TYPE_4DOUBLE || \
+     type == TYPE_16DOUBLE || \
+     type == TYPE_ARRAY_DOUBLE_OF_LENGTH_DEPENDING_ON_PREVIOUS_ARGS)
+
+#define NB_MAX_TEXTURES 16
+#define MY_GL_MAX_VERTEX_ATTRIBS_ARB 16
+#define MY_GL_MAX_VERTEX_ATTRIBS_NV 16
+#define MY_GL_MAX_VARIANT_POINTER_EXT 16
+
+typedef struct {
+    int ret_type;
+    int has_out_parameters;
+    int nb_args;
+    int args_type[0];
+} Signature;
+
+static const int vmgl_init32_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+static const int vmgl_init64_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+
+static const int vmgl_resize_surface_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+
+static const int vmgl_render_surface_signature[] =
+    { TYPE_NONE, 1, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_OUT_ARRAY_CHAR };
+
+/* XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attribList) */
+static const int glXChooseVisual_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT };
+
+/* GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis,
+ *         GLXContext shareList, Bool direct) */
+static const int glXCreateContext_signature[] =
+    { TYPE_INT, 0, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT };
+
+static const int glXCopyContext_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_INT };
+
+/* void glXDestroyContext(Display *dpy, GLXContext ctx) */
+static const int glXDestroyContext_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) */
+/* making it asynchronous */
+static const int glXMakeCurrent_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+/* int glXGetConfig(Display *dpy, XVisualInfo *visual, int attrib, int *value)
+ */
+static const int glXGetConfig_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+/* "glXGetConfig_extended"(dpy, visual_id, int n, int *attribs,
+ *         int *values, int* rets) */
+static const int glXGetConfig_extended_signature[] =
+    { TYPE_NONE, 1, 6, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_INT, TYPE_OUT_ARRAY_INT, TYPE_OUT_ARRAY_INT };
+
+/* void glXSwapBuffers(Display *dpy, GLXDrawable drawable) */
+static const int glXSwapBuffers_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* Bool glXQueryVersion(Display *dpy, int *maj, int *min) */
+static const int glXQueryVersion_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_OUT_1INT, TYPE_OUT_1INT };
+
+/* Bool glXQueryExtension(Display *dpy, int *errorBase, int *eventBase) */
+static const int glXQueryExtension_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_OUT_1INT, TYPE_OUT_1INT };
+
+static const int glXWaitGL_signature[] = { TYPE_INT, 0, 0 };
+static const int glXWaitX_signature[] = { TYPE_INT, 0, 0 };
+
+/* GLX 1.1 and later */
+
+/* const char *glXGetClientString(Display *dpy, int name) */
+static const int glXGetClientString_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* const char *glXQueryExtensionsString(Display *dpy, int screen) */
+static const int glXQueryExtensionsString_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* const char *glXQueryServerString(Display *dpy, int screen, int name) */
+static const int glXQueryServerString_signature[] =
+    { TYPE_CONST_CHAR, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+static const int glXGetProcAddress_fake_signature[] =
+    { TYPE_INT, 0, 1, TYPE_NULL_TERMINATED_STRING };
+
+static const int glXGetProcAddress_global_fake_signature[] =
+    { TYPE_NONE, 1, 3, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_OUT_ARRAY_CHAR };
+
+/* GLX 1.3 and later */
+
+/* GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen,
+ *         const int *attribList, int *nitems) */
+static const int glXChooseFBConfig_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT,
+      TYPE_OUT_1INT };
+
+static const int glXChooseFBConfigSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT,
+      TYPE_OUT_1INT };
+
+static const int glXGetFBConfigs_signature[] =
+    { TYPE_INT, 1, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_OUT_1INT };
+
+/* "glXGetFBConfigAttrib_extended"(dpy, fbconfig, int n, int *attribs,
+ *         int *values, int *rets) */
+static const int glXGetFBConfigAttrib_extended_signature[] =
+    { TYPE_NONE, 1, 6, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_INT, TYPE_OUT_ARRAY_INT, TYPE_OUT_ARRAY_INT };
+
+/* GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config,
+ *         const int *attribList) */
+static const int glXCreatePbuffer_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_ARRAY_INT };
+
+static const int glXCreateGLXPbufferSGIX_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_INT };
+
+static const int glXDestroyPbuffer_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXDestroyGLXPbufferSGIX_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config,
+ *         int renderType, GLXContext shareList, Bool direct) */
+static const int glXCreateNewContext_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT };
+
+static const int glXCreateContextWithConfigSGIX_signature[] =
+    { TYPE_INT, 0, 5, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT };
+
+/* XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config) */
+static const int glXGetVisualFromFBConfig_signature[] =
+    { TYPE_INT, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+/* int glXGetFBConfigAttrib(Display *dpy, GLXFBConfig  config,
+ *         int attribute, int *value) */
+static const int glXGetFBConfigAttrib_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+static const int glXGetFBConfigAttribSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+static const int glXQueryContext_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+static const int glXQueryGLXPbufferSGIX_signature[] =
+    { TYPE_INT, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+static const int glXQueryDrawable_signature[] =
+    { TYPE_NONE, 1, 4, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT,
+      TYPE_OUT_1INT };
+
+/* void glXUseXFont(Font font, int first, int count, int list) */
+static const int glXUseXFont_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+
+/* Bool glXIsDirect(Display *dpy, GLXContext ctx) */
+static const int glXIsDirect_signature[] =
+    { TYPE_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXGetScreenDriver_signature[] =
+    { TYPE_CONST_CHAR, 0, 2, TYPE_IN_IGNORED_POINTER, TYPE_INT };
+
+static const int glXGetDriverConfig_signature[] =
+    { TYPE_CONST_CHAR, 0, 1, TYPE_NULL_TERMINATED_STRING };
+
+
+static const int glXWaitVideoSyncSGI_signature[] =
+    { TYPE_INT, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_1INT };
+
+static const int glXGetVideoSyncSGI_signature[] =
+    { TYPE_INT, 1, 1, TYPE_OUT_1INT };
+
+static const int glXSwapIntervalSGI_signature[] =
+    { TYPE_INT, 0, 1, TYPE_INT };
+
+static const int glXBindTexImageATI_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXReleaseTexImageATI_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXBindTexImageARB_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+static const int glXReleaseTexImageARB_signature[] =
+    { TYPE_INT, 0, 3, TYPE_IN_IGNORED_POINTER, TYPE_INT, TYPE_INT };
+
+/* const GLubyte *glGetString(GLenum name) */
+static const int glGetString_signature[] =
+    { TYPE_CONST_CHAR, 0, 1, TYPE_INT };
+
+/* void glShaderSourceARB(GLhandleARB handle, GLsizei size,
+ *         const GLcharARB **p_tab_prog, const GLint *tab_length) */
+/* --> void glShaderSourceARB(GLhandleARB handle, GLsizei size,
+ *         const GLcharARB *all_progs, const GLint *tab_length) */
+static const int glShaderSourceARB_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_ARRAY_INT };
+static const int glShaderSource_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR, TYPE_ARRAY_INT };
+
+static const int glVertexPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glNormalPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glColorPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glSecondaryColorPointer_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glIndexPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glEdgeFlagPointer_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAttribPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 8, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAttribPointerNV_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glWeightPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glMatrixIndexPointerARB_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glFogCoordPointer_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glInterleavedArrays_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glElementPointerATI_fake_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVariantPointerEXT_fake_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glTuxRacerDrawElements_fake_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexAndNormalPointer_fake_signature[] =
+    { TYPE_NONE, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer01_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glTexCoordPointer012_fake_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glVertexNormalPointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 8, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalColorPointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 11, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexColorTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 12, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 11, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord01PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 14, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_ARRAY_CHAR };
+static const int glVertexNormalTexCoord012PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 17, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord0PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 14, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord01PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 17, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_ARRAY_CHAR };
+static const int
+    glVertexNormalColorTexCoord012PointerInterlaced_fake_signature[] =
+    { TYPE_NONE, 0, 20, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_ARRAY_CHAR };
+
+static const int glGenTextures_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int glGenBuffersARB_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int glGenLists_fake_signature[] = { TYPE_NONE, 0, 1, TYPE_INT };
+
+static const int vmglDrawElements_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglDrawRangeElements_buffer_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT };
+static const int vmglMultiDrawElements_buffer_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_ARRAY_INT, TYPE_INT, TYPE_ARRAY_INT,
+      TYPE_INT };
+
+static const int vmglVertexPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglNormalPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglColorPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglSecondaryColorPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglIndexPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglTexCoordPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglEdgeFlagPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_INT, TYPE_INT };
+static const int vmglVertexAttribPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 6, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT };
+static const int vmglWeightPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglMatrixIndexPointerARB_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglFogCoordPointer_buffer_signature[] =
+    { TYPE_NONE, 0, 3, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglVariantPointerEXT_buffer_signature[] =
+    { TYPE_NONE, 0, 4, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+
+static const int vmglReadPixels_pbo_signature[] =
+    { TYPE_INT, 0, 7, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT,
+      TYPE_INT, TYPE_INT };
+static const int vmglDrawPixels_pbo_signature[] =
+    { TYPE_NONE, 0, 5, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT };
+static const int vmglMapBufferARB_fake_signature[] =
+    { TYPE_INT, 1, 3, TYPE_INT, TYPE_INT, TYPE_OUT_ARRAY_CHAR };
+
+static const int vmglSelectBuffer_fake_signature[] =
+    { TYPE_NONE, 0, 1, TYPE_INT };
+static const int vmglGetSelectBuffer_fake_signature[] =
+    { TYPE_NONE, 1, 1, TYPE_ARRAY_CHAR };
+static const int vmglFeedbackBuffer_fake_signature[] =
+    { TYPE_NONE, 0, 2, TYPE_INT, TYPE_INT };
+static const int vmglGetFeedbackBuffer_fake_signature[] =
+    { TYPE_NONE, 1, 1, TYPE_ARRAY_CHAR };
+
+static const int vmglGetError_fake_signature[] = { TYPE_NONE, 0, 0 };
+
+#include "opengl-func.h"
+
+#define IS_NULL_POINTER_OK_FOR_FUNC(func_number) \
+    (func_number == glBitmap_func || \
+     func_number == glTexImage1D_func || \
+     func_number == glTexImage2D_func || \
+     func_number == glTexImage3D_func || \
+     func_number == glBufferDataARB_func || \
+     func_number == glNewObjectBufferATI_func)
+
+#endif
diff --git a/gl/vmgl-process.h b/gl/vmgl-process.h
new file mode 100644
index 0000000..9558ece
--- /dev/null
+++ b/gl/vmgl-process.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010 Intel Corporation
+ * Authors:
+ *   Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISiNG FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+struct ProcessStruct {
+    int process_id;
+    int wordsize;
+    int rq_l, rrq_l;
+    int sum;
+    char *rq, *rq_p;
+    char *rrq, *rrq_p;
+};
diff --git a/gl/vmgl.h b/gl/vmgl.h
new file mode 100644
index 0000000..7d656b7
--- /dev/null
+++ b/gl/vmgl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2006,2007 Even Rouault
+ * Authors:
+ *   Even Rouault
+ *   Andrzej Zaborowski
+ *   Gordon Williams <gordon.williams@collabora.co.uk>
+ *   Ian Molton <ian.molton@collabora.co.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+typedef struct ProcessStruct ProcessStruct;
+
+void vmgl_disconnect(ProcessStruct *process);
+ProcessStruct *vmgl_get_process(pid_t pid);
+int vmgl_decode_call(ProcessStruct *process, const uint8_t *in_args,
+                int args_len, uint8_t *r_buffer);
+int vmgl_acceleration_capability_check(void);
