Patchwork [3/6,v2] gl: OpenGL passthrough implementation.

login
register
mail settings
Submitter Andrzej Zaborowski
Date Feb. 22, 2012, 11:22 p.m.
Message ID <1329952970-356-3-git-send-email-andrew.zaborowski@intel.com>
Download mbox | patch
Permalink /patch/142591/
State New
Headers show

Comments

Andrzej Zaborowski - Feb. 22, 2012, 11:22 p.m.
Building of the whole thing can be enabled or disabled by configure
switches --enable-gl / --disable-gl, default is to autodetect
OpenGL headers/libraries presence on the host.

The gl subdirectory contains the whole framework which takes
command buffers from whatever the transport mechanism between guest
and host is (such as virtio), executes the commands and writes
response buffers to be sent back to the guest.  The API is quite
simple.

Guest processes are identified by their PIDs and each process should
have a completely separate environment.  The rest is OpenGL
passthrough, with some resource/call buffering/grouping and other smarts.

Signed-off-by: Andrzej Zaborowski <andrew.zaborowski@intel.com>
---
v2: keep track of enabled AttribArrays on the host to prevent buffer
  overruns by malicious guest.  Bug fixes, clean-up, remove unnecessary
  file.  Integrate clean-up from Alon Levy.
---
 Makefile.target      |   14 +
 configure            |   42 +
 gl/range_alloc.h     |  195 +++
 gl/vmgl-exec.c       | 3535 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gl/vmgl-func-perso.h |  120 ++
 gl/vmgl-func.h       |  611 +++++++++
 gl/vmgl-process.h    |   32 +
 gl/vmgl.h            |   34 +
 8 files changed, 4583 insertions(+), 0 deletions(-)
 create mode 100644 gl/range_alloc.h
 create mode 100644 gl/vmgl-exec.c
 create mode 100644 gl/vmgl-func-perso.h
 create mode 100644 gl/vmgl-func.h
 create mode 100644 gl/vmgl-process.h
 create mode 100644 gl/vmgl.h

Patch

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);