diff --git a/gl/gloffscreen-common.c b/gl/gloffscreen-common.c
new file mode 100644
index 0000000..2142715
--- /dev/null
+++ b/gl/gloffscreen-common.c
@@ -0,0 +1,579 @@
+/*
+ * Offscreen OpenGL abstraction layer - Common utilities
+ *
+ * Copyright (c) 2010-2012 Intel Corporation
+ * Authors:
+ *   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.
+ */
+
+#ifdef _WIN32
+#include <windows.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#include "gloffscreen.h"
+#include "sysemu.h"
+
+/*
+ * (Copied from glx.h because we need these on windows too)
+ * Tokens for glXChooseVisual and glXGetConfig:
+ */
+#define GLX_USE_GL		1
+#define GLX_BUFFER_SIZE		2
+#define GLX_LEVEL		3
+#define GLX_RGBA		4
+#define GLX_DOUBLEBUFFER	5
+#define GLX_STEREO		6
+#define GLX_AUX_BUFFERS		7
+#define GLX_RED_SIZE		8
+#define GLX_GREEN_SIZE		9
+#define GLX_BLUE_SIZE		10
+#define GLX_ALPHA_SIZE		11
+#define GLX_DEPTH_SIZE		12
+#define GLX_STENCIL_SIZE	13
+#define GLX_ACCUM_RED_SIZE	14
+#define GLX_ACCUM_GREEN_SIZE	15
+#define GLX_ACCUM_BLUE_SIZE	16
+#define GLX_ACCUM_ALPHA_SIZE	17
+/*
+ * GLX 1.3 and later:
+ */
+#define GLX_CONFIG_CAVEAT		0x20
+#define GLX_DONT_CARE			0xFFFFFFFF
+#define GLX_X_VISUAL_TYPE		0x22
+#define GLX_TRANSPARENT_TYPE		0x23
+#define GLX_TRANSPARENT_INDEX_VALUE	0x24
+#define GLX_TRANSPARENT_RED_VALUE	0x25
+#define GLX_TRANSPARENT_GREEN_VALUE	0x26
+#define GLX_TRANSPARENT_BLUE_VALUE	0x27
+#define GLX_TRANSPARENT_ALPHA_VALUE	0x28
+#define GLX_WINDOW_BIT			0x00000001
+#define GLX_NONE			0x8000
+#define GLX_TRUE_COLOR			0x8002
+#define GLX_VISUAL_ID			0x800B
+#define GLX_DRAWABLE_TYPE		0x8010
+#define GLX_RENDER_TYPE			0x8011
+#define GLX_X_RENDERABLE		0x8012
+#define GLX_FBCONFIG_ID			0x8013
+#define GLX_RGBA_TYPE			0x8014
+#define GLX_MAX_PBUFFER_WIDTH		0x8016
+#define GLX_MAX_PBUFFER_HEIGHT		0x8017
+#define GLX_MAX_PBUFFER_PIXELS		0x8018
+#define GLX_LARGEST_PBUFFER		0x801C
+#define GLX_RGBA_BIT			0x00000001
+
+int glo_flags_get_depth_bits(int format_flags)
+{
+    switch (format_flags & GLO_FF_DEPTH_MASK) {
+    case GLO_FF_DEPTH_16:
+        return 16;
+    case GLO_FF_DEPTH_24:
+        return 24;
+    case GLO_FF_DEPTH_32:
+        return 32;
+    default:
+        return 0;
+    }
+}
+
+int glo_flags_get_stencil_bits(int format_flags)
+{
+    switch (format_flags & GLO_FF_STENCIL_MASK) {
+    case GLO_FF_STENCIL_8:
+        return 8;
+    default:
+        return 0;
+    }
+}
+
+void glo_flags_get_rgba_bits(int format_flags, int *rgba)
+{
+    int alpha = (format_flags & GLO_FF_ALPHA) != 0;
+
+    switch (format_flags & GLO_FF_BITS_MASK) {
+    case GLO_FF_BITS_16:
+        rgba[0] = alpha ? 4 : 5;
+        rgba[1] = alpha ? 4 : 6;
+        rgba[2] = alpha ? 4 : 5;
+        rgba[3] = alpha ? 4 : 0;
+        break;
+    case GLO_FF_BITS_24:
+        /* ignore alpha */
+        rgba[0] = 8;
+        rgba[1] = 8;
+        rgba[2] = 8;
+        rgba[3] = 0;
+        break;
+    case GLO_FF_BITS_32:
+        rgba[0] = 8;
+        rgba[1] = 8;
+        rgba[2] = 8;
+        rgba[3] = 8;
+        break;
+    default:
+        rgba[0] = 8;
+        rgba[1] = 8;
+        rgba[2] = 8;
+        rgba[3] = 0;
+        break;
+    }
+}
+
+int glo_flags_get_bytes_per_pixel(int format_flags)
+{
+    switch (format_flags & GLO_FF_BITS_MASK) {
+    case GLO_FF_BITS_16:
+        return 2;
+    case GLO_FF_BITS_24:
+        return 3;
+    case GLO_FF_BITS_32:
+        return 4;
+    default:
+        return 3;
+    }
+}
+
+void glo_flags_get_readpixel_type(int format_flags,
+                int *gl_format, int *gl_type)
+{
+    GLenum gformat, gtype;
+
+    if (format_flags & GLO_FF_ALPHA) {
+        switch (format_flags & GLO_FF_BITS_MASK) {
+        case GLO_FF_BITS_16:
+            gformat = GL_RGBA;
+            gtype = GL_UNSIGNED_SHORT_4_4_4_4;
+            break;
+        case GLO_FF_BITS_24:
+        case GLO_FF_BITS_32:
+        default:
+            gformat = GL_BGRA;
+            gtype = GL_UNSIGNED_BYTE;
+            break;
+        }
+    } else {
+        switch (format_flags & GLO_FF_BITS_MASK) {
+        case GLO_FF_BITS_16:
+            gformat = GL_RGB;
+            gtype = GL_UNSIGNED_SHORT_5_6_5;
+            break;
+        case GLO_FF_BITS_24:
+        case GLO_FF_BITS_32:
+        default:
+            gformat = GL_BGR;
+            gtype = GL_UNSIGNED_BYTE;
+            break;
+        }
+    }
+
+    if (gl_format) {
+        *gl_format = gformat;
+    }
+    if (gl_type) {
+        *gl_type = gtype;
+    }
+}
+
+int glo_flags_score(int format_flags_expected, int format_flags_real)
+{
+    int score = 1;
+
+    if (format_flags_expected == format_flags_real) {
+        return 0;
+    }
+
+    /* we wanted alpha, but we didn't get it */
+    if ((format_flags_expected & GLO_FF_ALPHA_MASK) <
+            (format_flags_real & GLO_FF_ALPHA_MASK)) {
+        score++;
+    }
+
+    /* fewer bits than we expected */
+    if ((format_flags_expected & GLO_FF_BITS_MASK) <
+            (format_flags_real & GLO_FF_BITS_MASK)) {
+        score++;
+    }
+
+    /* fewer depth bits than we expected */
+    if ((format_flags_expected & GLO_FF_DEPTH_MASK) <
+            (format_flags_real & GLO_FF_DEPTH_MASK)) {
+        score++;
+    }
+
+    /* fewer stencil bits than we expected */
+    if ((format_flags_expected & GLO_FF_STENCIL_MASK) <
+            (format_flags_real & GLO_FF_STENCIL_MASK)) {
+        score++;
+    }
+
+    return score;
+}
+
+int glo_flags_get_from_glx(const uint32_t *fb_config, int assume_booleans)
+{
+    int buffer_size = 0;
+    int depth_size = 0;
+    int stencil_size = 0;
+    int rgba_size[] = { 0, 0, 0, 0 };
+    int flags = 0;
+
+    while (*fb_config) {
+        int is_single = 0;
+        switch (*fb_config) {
+        case GLX_USE_GL:
+            is_single = 1;
+            break;
+        case GLX_BUFFER_SIZE:
+            buffer_size = fb_config[1];
+            break;
+        case GLX_LEVEL:
+            break;
+        case GLX_RGBA:
+            flags |= GLO_FF_ALPHA;
+            break;
+        case GLX_DOUBLEBUFFER:
+            is_single = 1;
+            break;
+        case GLX_STEREO:
+            is_single = 1;
+            break;
+        case GLX_AUX_BUFFERS:
+            break;
+        case GLX_RED_SIZE:
+            rgba_size[0] = fb_config[1];
+            break;
+        case GLX_GREEN_SIZE:
+            rgba_size[1] = fb_config[1];
+            break;
+        case GLX_BLUE_SIZE:
+            rgba_size[2] = fb_config[1];
+            break;
+        case GLX_ALPHA_SIZE:
+            rgba_size[3] = fb_config[1];
+            break;
+        case GLX_DEPTH_SIZE:
+            depth_size = fb_config[1];
+            break;
+        case GLX_STENCIL_SIZE:
+            stencil_size = fb_config[1];
+            break;
+        case GLX_ACCUM_RED_SIZE:
+        case GLX_ACCUM_GREEN_SIZE:
+        case GLX_ACCUM_BLUE_SIZE:
+        case GLX_ACCUM_ALPHA_SIZE:
+            break;
+        }
+
+        /* Next */
+        if (is_single && assume_booleans) {
+            fb_config++;
+        } else {
+            fb_config += 2;
+        }
+    }
+
+    if (rgba_size[3]) {
+        flags |= GLO_FF_ALPHA;
+    }
+
+    /* Ensure we have room for *some* alpha */
+    if ((flags & GLO_FF_ALPHA) && rgba_size[3] == 0) {
+        rgba_size[3] = 1;
+    }
+
+    /* Buffer size flag */
+    if (buffer_size == 0) {
+        buffer_size = rgba_size[0] + rgba_size[1] + rgba_size[2] + rgba_size[3];
+        buffer_size = (flags & GLO_FF_ALPHA) ? 32 : 24;
+    }
+    if (buffer_size <= 16) {
+        flags |= GLO_FF_BITS_16;
+    } else if (buffer_size <= 24) {
+        flags |= GLO_FF_BITS_24;
+    } else {
+        flags |= GLO_FF_BITS_32;
+    }
+
+    /* Depth */
+    if (depth_size <= 16) {
+        flags |= GLO_FF_DEPTH_16;
+    } else if (depth_size <= 24) {
+        flags |= GLO_FF_DEPTH_24;
+    } else {
+        flags |= GLO_FF_DEPTH_32;
+    }
+
+    /* Stencil */
+    if (stencil_size > 0) {
+        flags |= GLO_FF_STENCIL_8;
+    }
+
+    return flags;
+}
+
+void glo_surface_getcontents_readpixels(int format_flags, int stride, int bpp,
+                int width, int height, void *data)
+{
+    int gl_format, gl_type, rl, pa;
+    static int once;
+
+    glo_flags_get_readpixel_type(format_flags, &gl_format, &gl_type);
+    switch(bpp) {
+    case 24:
+        if (gl_format != GL_BGR) {
+            if (!once) {
+                fprintf(stderr, "vmgl: Warning: compressing alpha\n");
+                once = 1;
+            }
+            gl_format = GL_BGR;
+        }
+        break;
+    case 32:
+        if (gl_format != GL_BGRA) {
+            fprintf(stderr, "vmgl: Warning: expanding alpha!\n");
+            gl_format = GL_BGRA;
+        }
+        break;
+    default:
+        fprintf(stderr, "vmgl: Warning: unsupported colourdepth\n");
+        break;
+    }
+
+    /* Save guest processes GL state before we ReadPixels() */
+    glGetIntegerv(GL_PACK_ROW_LENGTH, &rl);
+    glGetIntegerv(GL_PACK_ALIGNMENT, &pa);
+    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_PACK_ALIGNMENT, 4);
+
+#ifdef GETCONTENTS_INDIVIDUAL
+    GLubyte *b = (GLubyte *) data;
+    int irow;
+
+    for (irow = height - 1; irow >= 0; irow--) {
+        glReadPixels(0, irow, width, 1, gl_format, gl_type, b);
+        b += stride;
+    }
+#else
+    /* Faster buffer flip */
+    GLubyte *b = (GLubyte *) data;
+    GLubyte *c = &((GLubyte *) data)[stride * (height - 1)];
+    GLubyte *tmp = (GLubyte*) g_malloc(stride);
+    int irow;
+
+    glReadPixels(0, 0, width, height, gl_format, gl_type, data);
+
+    for (irow = 0; irow < height / 2; irow++) {
+        memcpy(tmp, b, stride);
+        memcpy(b, c, stride);
+        memcpy(c, tmp, stride);
+        b += stride;
+        c -= stride;
+    }
+    g_free(tmp);
+#endif
+
+    /* Restore GL state */
+    glPixelStorei(GL_PACK_ROW_LENGTH, rl);
+    glPixelStorei(GL_PACK_ALIGNMENT, pa);
+}
+
+uint32_t glo_get_glx_from_flags(int format_flags, int glx_enum)
+{
+    int rgba[4];
+
+    glo_flags_get_rgba_bits(format_flags, rgba);
+    switch (glx_enum) {
+    case GLX_USE_GL:
+        return 1;
+    case GLX_BUFFER_SIZE:
+        return glo_flags_get_bytes_per_pixel(format_flags) * 8;
+    case GLX_LEVEL:
+        return 0;
+    case GLX_RGBA:
+        return format_flags & GLO_FF_ALPHA;
+    case GLX_DOUBLEBUFFER:
+        return 1;
+    case GLX_STEREO:
+        return 0;
+    case GLX_AUX_BUFFERS:
+        return 0;
+    case GLX_RED_SIZE:
+        return rgba[0];
+    case GLX_GREEN_SIZE:
+        return rgba[1];
+    case GLX_BLUE_SIZE:
+        return rgba[2];
+    case GLX_ALPHA_SIZE:
+        return rgba[3];
+    case GLX_DEPTH_SIZE:
+        return glo_flags_get_depth_bits(format_flags);
+    case GLX_STENCIL_SIZE:
+        return glo_flags_get_stencil_bits(format_flags);
+    case GLX_ACCUM_RED_SIZE:
+    case GLX_ACCUM_GREEN_SIZE:
+    case GLX_ACCUM_BLUE_SIZE:
+    case GLX_ACCUM_ALPHA_SIZE:
+        return 0;
+
+    /* The attributes for glXGetFBConfigAttrib */
+    case GLX_FBCONFIG_ID:
+        return 0;
+    case GLX_RENDER_TYPE:
+        return GLX_RGBA_BIT;
+    case GLX_DRAWABLE_TYPE:
+        return GLX_WINDOW_BIT;
+    case GLX_X_RENDERABLE:
+        return 1;
+    case GLX_VISUAL_ID:
+    case GLX_X_VISUAL_TYPE:
+        /* The real value is obtained client-side.  */
+        return 0;
+    case GLX_CONFIG_CAVEAT:
+        return GLX_NONE;
+    case GLX_TRANSPARENT_TYPE:
+        return GLX_NONE;
+    case GLX_TRANSPARENT_INDEX_VALUE:
+    case GLX_TRANSPARENT_RED_VALUE:
+    case GLX_TRANSPARENT_GREEN_VALUE:
+    case GLX_TRANSPARENT_BLUE_VALUE:
+    case GLX_TRANSPARENT_ALPHA_VALUE:
+        return 0;
+    case GLX_MAX_PBUFFER_WIDTH:
+    case GLX_MAX_PBUFFER_HEIGHT:
+    case GLX_MAX_PBUFFER_PIXELS:
+        return 0;
+    }
+
+    return 0;
+}
+
+int glo_acceleration_capability_check(void)
+{
+    int test_failure = 0;
+    GloContext *context;
+    GloSurface *surface;
+
+#define TX 32
+#define TY 32
+    uint8_t *datain = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *datain_flip = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *dataout = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *p;
+    int x, y;
+    uint32_t buffer_attributes[] = {
+        GLX_RED_SIZE,      8,
+        GLX_GREEN_SIZE,    8,
+        GLX_BLUE_SIZE,     8,
+        GLX_ALPHA_SIZE,    8,
+        GLX_DEPTH_SIZE,    0,
+        GLX_STENCIL_SIZE,  0,
+        0,
+    };
+    int buffer_flags = glo_flags_get_from_glx(buffer_attributes, 0);
+    int bpp = glo_flags_get_bytes_per_pixel(buffer_flags);
+    int gl_format, gl_type;
+
+    if (glo_sanity_test() != 0) {
+        return 1;
+    }
+
+    memset(datain_flip, 0, TX * TY * 4);
+    memset(datain, 0, TX * TY * 4);
+
+    p = datain;
+    for (y = 0; y < TY; y++) {
+        for (x = 0; x < TX; x++) {
+            p[0] = x;
+            p[1] = y;
+            if (bpp > 2) {
+                p[2] = 0;
+            }
+            if (bpp > 3) {
+                p[3] = 0xff;
+            }
+            p += bpp;
+        }
+        memcpy(&datain_flip[((TY - 1) - y) * bpp * TX],
+                        &datain[y * bpp * TX], bpp * TX);
+    }
+
+    glo_init();
+    /* new surface */
+    context = glo_context_create(buffer_flags, 0);
+    if (!context) {
+        test_failure = 1;
+        goto test_end;
+    }
+    surface = glo_surface_create(TX, TY, context);
+    if (!surface) {
+        glo_context_destroy(context);
+        test_failure = 1;
+        goto test_end;
+    }
+    glo_surface_makecurrent(surface);
+
+    if (strstr((const char *) glGetString(GL_RENDERER), "Software")) {
+        /* Host does not have OpenGL hardware acceleration..
+         * Note that most of the time (i.e. without cpu virtualisation)
+         * software rendering on the host is still going to be way
+         * faster than software rendering on the guest.  A much better
+         * solution would be for the guest to send a rough benchmark
+         * result inside the _init command so that it can be compared
+         * against host performance.
+         */
+        test_failure = 1;
+        goto test_end;
+    }
+
+    /* fill with stuff (in correctly ordered way) */
+    glClear(GL_COLOR_BUFFER_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, TX, 0, TY, 0, 1);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glRasterPos2f(0, 0);
+    glo_flags_get_readpixel_type(buffer_flags, &gl_format, &gl_type);
+    glDrawPixels(TX, TY, gl_format, gl_type, datain_flip);
+    glFlush();
+
+    memset(dataout, 0, bpp * TX * TY);
+
+    glo_surface_getcontents(surface, TX * bpp, bpp * 8, dataout);
+
+    /* destroy surface */
+    glo_surface_destroy(surface);
+    glo_context_destroy(context);
+    /* compare */
+    if (memcmp(datain, dataout, bpp * TX * TY) != 0) {
+        test_failure = 1;
+    }
+
+test_end:
+    g_free(datain);
+    g_free(datain_flip);
+    g_free(dataout);
+    return test_failure;
+}
diff --git a/gl/gloffscreen-wgl.c b/gl/gloffscreen-wgl.c
new file mode 100644
index 0000000..1073085
--- /dev/null
+++ b/gl/gloffscreen-wgl.c
@@ -0,0 +1,832 @@
+/*
+ * Offscreen OpenGL abstraction layer - WGL (windows) specific
+ *
+ * Copyright (c) 2010 Intel Corporation
+ * Authors:
+ *   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 <windows.h>
+#include <wingdi.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/wglext.h>
+
+#include "gloffscreen.h"
+#include "sysemu.h"
+
+/* In Windows, you must create a window *before* you can create a pbuffer or
+ * get a context.  So we create a hidden Window on startup
+ * (see glo_init/GloMain).
+ *
+ * Also, you can't share contexts that have different pixel formats, so we
+ * can't just create a new context from the window. We must create a whole
+ * new PBuffer just for a context :(
+ */
+
+static struct GloMain {
+    HINSTANCE hInstance;
+    HDC       hDC;
+    HWND      hWnd; /* Our hidden window */
+    HGLRC     hContext;
+} glo;
+static int glo_inited = 0;
+
+struct GloContext {
+    int         format_flags;
+
+    /* Pixel format returned by wglChoosePixelFormat */
+    int         wglPixelFormat;
+    /* We need a pbuffer to make a context of the right pixel_format :( */
+    HPBUFFERARB hPBuffer;
+    HDC         hDC;
+    HGLRC       hContext;
+};
+
+struct GloSurface {
+    GLuint      width;
+    GLuint      height;
+
+    GloContext  *context;
+    HPBUFFERARB hPBuffer;
+    HDC         hDC;
+};
+
+#define GLO_WINDOW_CLASS "QEmuGLClass"
+#define DEFAULT_DEPTH_BUFFER 16
+
+static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+static PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
+static PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+static PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
+static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
+
+int glo_initialised(void)
+{
+    return glo_inited;
+}
+
+/* Sanity test of the host GL capabilities to see whether gloffscreen
+ * requirements are well supported */
+int glo_sanity_test(void)
+{
+    PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
+    PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
+    PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
+    PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
+    PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
+
+    wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)
+            wglGetProcAddress("wglChoosePixelFormatARB");
+    wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)
+            wglGetProcAddress("wglGetPbufferDCARB");
+    wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)
+            wglGetProcAddress("wglReleasePbufferDCARB");
+    wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)
+            wglGetProcAddress("wglCreatePbufferARB");
+    wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)
+            wglGetProcAddress("wglDestroyPbufferARB");
+    if (!wglChoosePixelFormatARB || !wglGetPbufferDCARB ||
+            !wglReleasePbufferDCARB || !wglCreatePbufferARB ||
+            !wglDestroyPbufferARB) {
+        fprintf(stderr, "vmgl: Unable to load the required WGL extensions\n");
+        return 1;
+    }
+
+    /* Check for shader support.  It is for mcompositor to run.  */
+
+    if (!wglGetProcAddress("glShaderSource")) {
+        fprintf(stderr, "vmgl: Unable to find shader support\n");
+        return 1;
+    }
+    return 0;
+}
+
+/* Initialise gloffscreen */
+void glo_init(void)
+{
+    WNDCLASSEX wcx;
+    PIXELFORMATDESCRIPTOR pfd;
+    unsigned int pixel_format;
+
+    if (glo_inited) {
+        return 0;
+    }
+
+    glo.hInstance = GetModuleHandle(NULL); /* Grab an instance for our window */
+
+    wcx.cbSize = sizeof(wcx);
+    wcx.style = 0;
+    wcx.lpfnWndProc = DefWindowProc;
+    wcx.cbClsExtra = 0;
+    wcx.cbWndExtra = 0;
+    wcx.hInstance = glo.hInstance;
+    wcx.hIcon = NULL;
+    wcx.hCursor = NULL;
+    wcx.hbrBackground = NULL;
+    wcx.lpszMenuName =  NULL;
+    wcx.lpszClassName = GLO_WINDOW_CLASS;
+    wcx.hIconSm = NULL;
+    RegisterClassEx(&wcx);
+
+    glo.hWnd = CreateWindow(GLO_WINDOW_CLASS, "QEmuGL", 0, 0, 0, 0, 0,
+                    NULL, NULL, glo.hInstance, NULL);
+    if (!glo.hWnd) {
+        fprintf(stderr, "vmgl: Unable to create window\n");
+        return -1;
+    }
+    glo.hDC = GetDC(glo.hWnd);
+
+    memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
+    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+    pfd.nVersion = 1;
+    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+    pfd.iPixelType = PFD_TYPE_RGBA;
+    pfd.cColorBits = 24;
+    pfd.iLayerType = PFD_MAIN_PLANE;
+
+    pixel_format = ChoosePixelFormat(glo.hDC, &pfd);
+    DescribePixelFormat(glo.hDC, pixel_format,
+                    sizeof(PIXELFORMATDESCRIPTOR), &pfd);
+    if (!SetPixelFormat(glo.hDC, pixel_format, &pfd)) {
+        /* FIXME: free resources, if any */
+        return;
+    }
+
+    glo.hContext = wglCreateContext(glo.hDC);
+    if (glo.hContext == NULL) {
+        fprintf(stderr, "vmgl: Unable to create GL context\n");
+        /* FIXME: free resources */
+        return -1;
+    }
+    wglMakeCurrent(glo.hDC, glo.hContext);
+
+    /* FIXME: GW, Need to share lists AND copy state */
+
+    /* Load in the extensions we need */
+    wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)
+            wglGetProcAddress("wglChoosePixelFormatARB");
+    wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)
+            wglGetProcAddress("wglGetPbufferDCARB");
+    wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)
+            wglGetProcAddress("wglReleasePbufferDCARB");
+    wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)
+            wglGetProcAddress("wglCreatePbufferARB");
+    wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)
+            wglGetProcAddress("wglDestroyPbufferARB");
+    if (!wglChoosePixelFormatARB || !wglGetPbufferDCARB ||
+            !wglReleasePbufferDCARB || !wglCreatePbufferARB ||
+            !wglDestroyPbufferARB) {
+        fprintf(stderr, "vmgl: Unable to load the required WGL extensions\n");
+        /* FIXME: free resources */
+        return -1;
+    }
+
+    glo_inited = 1;
+
+    return 0;
+}
+
+/* Uninitialise gloffscreen */
+void glo_kill(void)
+{
+    if (glo.hContext) {
+        wglMakeCurrent(NULL, NULL);
+        wglDeleteContext(glo.hContext);
+        glo.hContext = NULL;
+    }
+    if (glo.hDC) {
+        ReleaseDC(glo.hWnd, glo.hDC);
+        glo.hDC = NULL;
+    }
+    if (glo.hWnd) {
+        DestroyWindow(glo.hWnd);
+        glo.hWnd = NULL;
+    }
+    UnregisterClass(GLO_WINDOW_CLASS, glo.hInstance);
+}
+
+const char *glo_glxqueryextensionsstring(void)
+{
+    return "";
+}
+
+static const char *standard_gl_functions ={
+    /* Miscellaneous */
+    "glClearIndex\0"
+    "glClearColor\0"
+    "glClear\0"
+    "glIndexMask\0"
+    "glColorMask\0"
+    "glAlphaFunc\0"
+    "glBlendFunc\0"
+    "glLogicOp\0"
+    "glCullFace\0"
+    "glFrontFace\0"
+    "glPointSize\0"
+    "glLineWidth\0"
+    "glLineStipple\0"
+    "glPolygonMode\0"
+    "glPolygonOffset\0"
+    "glPolygonStipple\0"
+    "glGetPolygonStipple\0"
+    "glEdgeFlag\0"
+    "glEdgeFlagv\0"
+    "glScissor\0"
+    "glClipPlane\0"
+    "glGetClipPlane\0"
+    "glDrawBuffer\0"
+    "glReadBuffer\0"
+    "glEnable\0"
+    "glDisable\0"
+    "glIsEnabled\0"
+    "glEnableClientState\0"
+    "glDisableClientState\0"
+    "glGetBooleanv\0"
+    "glGetDoublev\0"
+    "glGetFloatv\0"
+    "glGetIntegerv\0"
+    "glPushAttrib\0"
+    "glPopAttrib\0"
+    "glPushClientAttrib\0"
+    "glPopClientAttrib\0"
+    "glRenderMode\0"
+    "glGetError\0"
+    "glGetString\0"
+    "glFinish\0"
+    "glFlush\0"
+    "glHint\0"
+    /* Depth Buffer */
+    "glClearDepth\0"
+    "glDepthFunc\0"
+    "glDepthMask\0"
+    "glDepthRange\0"
+    /* Accumulation Buffer */
+    "glClearAccum\0"
+    "glAccum\0"
+    /* Transformation */
+    "glMatrixMode\0"
+    "glOrtho\0"
+    "glFrustum\0"
+    "glViewport\0"
+    "glPushMatrix\0"
+    "glPopMatrix\0"
+    "glLoadIdentity\0"
+    "glLoadMatrixd\0"
+    "glLoadMatrixf\0"
+    "glMultMatrixd\0"
+    "glMultMatrixf\0"
+    "glRotated\0"
+    "glRotatef\0"
+    "glScaled\0"
+    "glScalef\0"
+    "glTranslated\0"
+    "glTranslatef\0"
+    /* Display Lists */
+    "glIsList\0"
+    "glDeleteLists\0"
+    "glGenLists\0"
+    "glNewList\0"
+    "glEndList\0"
+    "glCallList\0"
+    "glCallLists\0"
+    "glListBase\0"
+    /* Drawing Functions */
+    "glBegin\0"
+    "glEnd\0"
+    "glVertex2d\0"
+    "glVertex2f\0"
+    "glVertex2i\0"
+    "glVertex2s\0"
+    "glVertex3d\0"
+    "glVertex3f\0"
+    "glVertex3i\0"
+    "glVertex3s\0"
+    "glVertex4d\0"
+    "glVertex4f\0"
+    "glVertex4i\0"
+    "glVertex4s\0"
+    "glVertex2dv\0"
+    "glVertex2fv\0"
+    "glVertex2iv\0"
+    "glVertex2sv\0"
+    "glVertex3dv\0"
+    "glVertex3fv\0"
+    "glVertex3iv\0"
+    "glVertex3sv\0"
+    "glVertex4dv\0"
+    "glVertex4fv\0"
+    "glVertex4iv\0"
+    "glVertex4sv\0"
+    "glNormal3b\0"
+    "glNormal3d\0"
+    "glNormal3f\0"
+    "glNormal3i\0"
+    "glNormal3s\0"
+    "glNormal3bv\0"
+    "glNormal3dv\0"
+    "glNormal3fv\0"
+    "glNormal3iv\0"
+    "glNormal3sv\0"
+    "glIndexd\0"
+    "glIndexf\0"
+    "glIndexi\0"
+    "glIndexs\0"
+    "glIndexub\0"
+    "glIndexdv\0"
+    "glIndexfv\0"
+    "glIndexiv\0"
+    "glIndexsv\0"
+    "glIndexubv\0"
+    "glColor3b\0"
+    "glColor3d\0"
+    "glColor3f\0"
+    "glColor3i\0"
+    "glColor3s\0"
+    "glColor3ub\0"
+    "glColor3ui\0"
+    "glColor3us\0"
+    "glColor4b\0"
+    "glColor4d\0"
+    "glColor4f\0"
+    "glColor4i\0"
+    "glColor4s\0"
+    "glColor4ub\0"
+    "glColor4ui\0"
+    "glColor4us\0"
+    "glColor3bv\0"
+    "glColor3dv\0"
+    "glColor3fv\0"
+    "glColor3iv\0"
+    "glColor3sv\0"
+    "glColor3ubv\0"
+    "glColor3uiv\0"
+    "glColor3usv\0"
+    "glColor4bv\0"
+    "glColor4dv\0"
+    "glColor4fv\0"
+    "glColor4iv\0"
+    "glColor4sv\0"
+    "glColor4ubv\0"
+    "glColor4uiv\0"
+    "glColor4usv\0"
+    "glTexCoord1d\0"
+    "glTexCoord1f\0"
+    "glTexCoord1i\0"
+    "glTexCoord1s\0"
+    "glTexCoord2d\0"
+    "glTexCoord2f\0"
+    "glTexCoord2i\0"
+    "glTexCoord2s\0"
+    "glTexCoord3d\0"
+    "glTexCoord3f\0"
+    "glTexCoord3i\0"
+    "glTexCoord3s\0"
+    "glTexCoord4d\0"
+    "glTexCoord4f\0"
+    "glTexCoord4i\0"
+    "glTexCoord4s\0"
+    "glTexCoord1dv\0"
+    "glTexCoord1fv\0"
+    "glTexCoord1iv\0"
+    "glTexCoord1sv\0"
+    "glTexCoord2dv\0"
+    "glTexCoord2fv\0"
+    "glTexCoord2iv\0"
+    "glTexCoord2sv\0"
+    "glTexCoord3dv\0"
+    "glTexCoord3fv\0"
+    "glTexCoord3iv\0"
+    "glTexCoord3sv\0"
+    "glTexCoord4dv\0"
+    "glTexCoord4fv\0"
+    "glTexCoord4iv\0"
+    "glTexCoord4sv\0"
+    "glRasterPos2d\0"
+    "glRasterPos2f\0"
+    "glRasterPos2i\0"
+    "glRasterPos2s\0"
+    "glRasterPos3d\0"
+    "glRasterPos3f\0"
+    "glRasterPos3i\0"
+    "glRasterPos3s\0"
+    "glRasterPos4d\0"
+    "glRasterPos4f\0"
+    "glRasterPos4i\0"
+    "glRasterPos4s\0"
+    "glRasterPos2dv\0"
+    "glRasterPos2fv\0"
+    "glRasterPos2iv\0"
+    "glRasterPos2sv\0"
+    "glRasterPos3dv\0"
+    "glRasterPos3fv\0"
+    "glRasterPos3iv\0"
+    "glRasterPos3sv\0"
+    "glRasterPos4dv\0"
+    "glRasterPos4fv\0"
+    "glRasterPos4iv\0"
+    "glRasterPos4sv\0"
+    "glRectd\0"
+    "glRectf\0"
+    "glRecti\0"
+    "glRects\0"
+    "glRectdv\0"
+    "glRectfv\0"
+    "glRectiv\0"
+    "glRectsv\0"
+    /* Lighting */
+    "glShadeModel\0"
+    "glLightf\0"
+    "glLighti\0"
+    "glLightfv\0"
+    "glLightiv\0"
+    "glGetLightfv\0"
+    "glGetLightiv\0"
+    "glLightModelf\0"
+    "glLightModeli\0"
+    "glLightModelfv\0"
+    "glLightModeliv\0"
+    "glMaterialf\0"
+    "glMateriali\0"
+    "glMaterialfv\0"
+    "glMaterialiv\0"
+    "glGetMaterialfv\0"
+    "glGetMaterialiv\0"
+    "glColorMaterial\0"
+    /* Raster functions */
+    "glPixelZoom\0"
+    "glPixelStoref\0"
+    "glPixelStorei\0"
+    "glPixelTransferf\0"
+    "glPixelTransferi\0"
+    "glPixelMapfv\0"
+    "glPixelMapuiv\0"
+    "glPixelMapusv\0"
+    "glGetPixelMapfv\0"
+    "glGetPixelMapuiv\0"
+    "glGetPixelMapusv\0"
+    "glBitmap\0"
+    "glReadPixels\0"
+    "glDrawPixels\0"
+    "glCopyPixels\0"
+    /* Stenciling */
+    "glStencilFunc\0"
+    "glStencilMask\0"
+    "glStencilOp\0"
+    "glClearStencil\0"
+    /* Texture mapping */
+    "glTexGend\0"
+    "glTexGenf\0"
+    "glTexGeni\0"
+    "glTexGendv\0"
+    "glTexGenfv\0"
+    "glTexGeniv\0"
+    "glGetTexGendv\0"
+    "glGetTexGenfv\0"
+    "glGetTexGeniv\0"
+    "glTexEnvf\0"
+    "glTexEnvi\0"
+    "glTexEnvfv\0"
+    "glTexEnviv\0"
+    "glGetTexEnvfv\0"
+    "glGetTexEnviv\0"
+    "glTexParameterf\0"
+    "glTexParameteri\0"
+    "glTexParameterfv\0"
+    "glTexParameteriv\0"
+    "glGetTexParameterfv\0"
+    "glGetTexParameteriv\0"
+    "glGetTexLevelParameterfv\0"
+    "glGetTexLevelParameteriv\0"
+    "glTexImage1D\0"
+    "glTexImage2D\0"
+    "glGetTexImage\0"
+    /* Evaluators */
+    "glMap1d\0"
+    "glMap1f\0"
+    "glMap2d\0"
+    "glMap2f\0"
+    "glGetMapdv\0"
+    "glGetMapfv\0"
+    "glGetMapiv\0"
+    "glEvalCoord1d\0"
+    "glEvalCoord1f\0"
+    "glEvalCoord1dv\0"
+    "glEvalCoord1fv\0"
+    "glEvalCoord2d\0"
+    "glEvalCoord2f\0"
+    "glEvalCoord2dv\0"
+    "glEvalCoord2fv\0"
+    "glMapGrid1d\0"
+    "glMapGrid1f\0"
+    "glMapGrid2d\0"
+    "glMapGrid2f\0"
+    "glEvalPoint1\0"
+    "glEvalPoint2\0"
+    "glEvalMesh1\0"
+    "glEvalMesh2\0"
+    /* Fog */
+    "glFogf\0"
+    "glFogi\0"
+    "glFogfv\0"
+    "glFogiv\0"
+    /* Selection and Feedback */
+    "glFeedbackBuffer\0"
+    "glPassThrough\0"
+    "glSelectBuffer\0"
+    "glInitNames\0"
+    "glLoadName\0"
+    "glPushName\0"
+    "glPopName\0"
+    /* 1.1 functions */
+    /* texture objects */
+    "glGenTextures\0"
+    "glDeleteTextures\0"
+    "glBindTexture\0"
+    "glPrioritizeTextures\0"
+    "glAreTexturesResident\0"
+    "glIsTexture\0"
+    /* texture mapping */
+    "glTexSubImage1D\0"
+    "glTexSubImage2D\0"
+    "glCopyTexImage1D\0"
+    "glCopyTexImage2D\0"
+    "glCopyTexSubImage1D\0"
+    "glCopyTexSubImage2D\0"
+    /* vertex arrays */
+    "glVertexPointer\0"
+    "glNormalPointer\0"
+    "glColorPointer\0"
+    "glIndexPointer\0"
+    "glTexCoordPointer\0"
+    "glEdgeFlagPointer\0"
+    "glGetPointerv\0"
+    "glArrayElement\0"
+    "glDrawArrays\0"
+    "glDrawElements\0"
+    "glInterleavedArrays\0"
+    /* GLX */
+    "glXChooseVisual\0"
+    "glXQueryExtensionsString\0"
+    "glXQueryServerString\0"
+    "glXGetClientString\0"
+    "glXCreateContext\0"
+    "glXCreateNewContext\0"
+    "glXCopyContext\0"
+    "glXDestroyContext\0"
+    "glXQueryVersion\0"
+    "glXMakeCurrent\0"
+    "glXSwapBuffers\0"
+    "glXGetConfig\0"
+    "glXQueryExtension\0"
+    "glXChooseFBConfig\0"
+    "glXGetFBConfigs\0"
+    "glXGetFBConfigAttrib\0"
+    "glXQueryContext\0"
+    "glXQueryDrawable\0"
+    "glXGetVisualFromFBConfig\0"
+    "glXIsDirect\0"
+    "\0"
+};
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+void *glo_getprocaddress(const char *proc_name)
+{
+    HGLRC old_ctx;
+    HDC old_dc;
+    void *proc_addr;
+
+    old_ctx = wglGetCurrentContext();
+    old_dc = wglGetCurrentDC();
+    if (old_dc != glo.hDC || old_ctx != glo.hContext) {
+        wglMakeCurrent(glo.hDC, glo.hContext);
+    }
+
+    proc_addr = wglGetProcAddress(proc_name);
+
+    if (old_dc != glo.hDC || old_ctx != glo.hContext) {
+        wglMakeCurrent(old_dc, old_ctx);
+    }
+
+    /* wGL doesn't know about the glx functions - but
+     * we never call these anyway (they're implemented in
+     * opengl_exec), so all we need to do is return a non-zero value...
+     *
+     * But we also have to check for 'standard' GL function names
+     * too as wGL doesn't return those either!  */
+    if (!proc_addr) {
+        const char *p = standard_gl_functions;
+        while (*p) {
+            if (!strcmp(proc_name, p)) {
+                proc_addr = (void *) 1;
+                break;
+            }
+            /* skip to the next '0' and then just over it */
+            while (*p) {
+                p++;
+            }
+            p++;
+        }
+    }
+
+    return proc_addr;
+}
+
+/* Create an OpenGL context for a certain pixel format. format_flags
+ * are made up of the GLO_ constants */
+GloContext *glo_context_create(int format_flags, GloContext *share_lists)
+{
+    GloContext *context;
+    int pf_attri[] = {
+        WGL_SUPPORT_OPENGL_ARB, TRUE,
+        WGL_DRAW_TO_PBUFFER_ARB, TRUE,
+        WGL_RED_BITS_ARB, 8,
+        WGL_GREEN_BITS_ARB, 8,
+        WGL_BLUE_BITS_ARB, 8,
+        WGL_ALPHA_BITS_ARB, 8,
+        WGL_DEPTH_BITS_ARB, 0,
+        WGL_STENCIL_BITS_ARB, 0,
+        WGL_DOUBLE_BUFFER_ARB, FALSE,
+        0
+    };
+    float pf_attrf[] = { 0, 0 };
+    unsigned int rgba_all = 0;
+    int pb_attr[] = { 0 };
+    int rgba_bits[4];
+
+    context = g_malloc0(sizeof(GloContext));
+    context->format_flags = format_flags;
+
+    /* Set up the surface format from the flags we were given */
+    glo_flags_get_rgba_bits(context->format_flags, rgba_bits);
+    pf_attri[5]  = rgba_bits[0];
+    pf_attri[7]  = rgba_bits[1];
+    pf_attri[9]  = rgba_bits[2];
+    pf_attri[11] = rgba_bits[3];
+    pf_attri[13] = glo_flags_get_depth_bits(context->format_flags);
+    pf_attri[15] = glo_flags_get_stencil_bits(context->format_flags);
+
+    /* Find out what pixel format to use */
+    wglChoosePixelFormatARB(glo.hDC, pf_attri, pf_attrf, 1,
+                    &context->wglPixelFormat, &rgba_all);
+    if (rgba_all == 0) {
+        g_free(context);
+        fprintf(stderr, "vmgl: No matching configs found.\n");
+        return NULL;
+    }
+
+    /* We create a tiny pbuffer - just so we can make a context
+     * of the right pixel format */
+    context->hPBuffer = wglCreatePbufferARB(glo.hDC,
+                    context->wglPixelFormat, 16, 16, pb_attr);
+    if (!context->hPBuffer) {
+        g_free(context);
+        fprintf(stderr, "vmgl: Couldn't create the PBuffer\n");
+        return NULL;
+    }
+    context->hDC = wglGetPbufferDCARB(context->hPBuffer);
+    if (!context->hDC) {
+        g_free(context);
+        /* TODO: free other resources, if any */
+        fprintf(stderr, "vmgl: Couldn't create the DC\n");
+        return NULL;
+    }
+
+    context->hContext = wglCreateContext(context->hDC);
+    if (context->hContext == NULL) {
+        g_free(context);
+        /* TODO: free other resources, if any */
+        fprintf(stderr, "vmgl: Unable to create GL context\n");
+        return NULL;
+    }
+
+    if (share_lists) {
+        /* Need to share lists... */
+        wglShareLists(share_lists->hContext, context->hContext);
+    }
+
+    return context;
+}
+
+/* Destroy a previouslu created OpenGL context */
+void glo_context_destroy(GloContext *context)
+{
+    if (!context) {
+        return;
+    }
+
+    wglMakeCurrent(NULL, NULL);
+    if (context->hPBuffer != NULL) {
+        wglReleasePbufferDCARB(context->hPBuffer, context->hDC);
+        wglDestroyPbufferARB(context->hPBuffer);
+    }
+    if (context->hDC != NULL) {
+        ReleaseDC(glo.hWnd, context->hDC);
+    }
+    if (context->hContext) {
+        wglDeleteContext(context->hContext);
+    }
+    free(context);
+}
+
+/* Create a surface with given width and height, format_flags are made up of
+ * the GLO_ constants */
+GloSurface *glo_surface_create(int width, int height, GloContext *context)
+{
+    GloSurface *surface;
+    int pb_attr[] = { 0 };
+
+    /* Create the p-buffer... */
+    surface = g_malloc0(sizeof(GloSurface));
+    surface->width = width;
+    surface->height = height;
+    surface->context = context;
+
+    surface->hPBuffer = wglCreatePbufferARB(glo.hDC,
+                    context->wglPixelFormat, surface->width,
+                    surface->height, pb_attr);
+    if (!surface->hPBuffer) {
+        g_free(surface);
+        fprintf(stderr, "vmgl: Couldn't create the PBuffer\n");
+        return NULL;
+    }
+    surface->hDC = wglGetPbufferDCARB(surface->hPBuffer);
+    if (!surface->hDC) {
+        g_free(surface);
+        /* TODO: Free other resources, if any */
+        fprintf(stderr, "vmgl: Couldn't create the DC\n");
+        return NULL;
+    }
+
+    return surface;
+}
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface)
+{
+    if (!surface) {
+        return;
+    }
+
+    wglMakeCurrent(NULL, NULL);
+    if (surface->hPBuffer != NULL) {
+        wglReleasePbufferDCARB(surface->hPBuffer, surface->hDC);
+        wglDestroyPbufferARB(surface->hPBuffer);
+    }
+    if (surface->hDC != NULL) {
+        ReleaseDC(glo.hWnd, surface->hDC);
+    }
+    g_free(surface);
+}
+
+/* Make the given surface current */
+int glo_surface_makecurrent(GloSurface *surface)
+{
+    if (surface) {
+        return wglMakeCurrent(surface->hDC, surface->context->hContext);
+    } else {
+        return wglMakeCurrent(NULL, NULL);
+    }
+}
+
+/* Get the contents of the given surface */
+void glo_surface_getcontents(GloSurface *surface,
+                int stride, int bpp, void *data)
+{
+    if (!surface) {
+        return;
+    }
+
+    /* Compatible / fallback method.  */
+    glo_surface_getcontents_readpixels(surface->context->format_flags,
+                    stride, bpp, surface->width, surface->height, data);
+}
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height)
+{
+    if (width) {
+        *width = surface->width;
+    }
+    if (height)
+        *height = surface->height;
+    }
+}
diff --git a/gl/gloffscreen-xcomposite.c b/gl/gloffscreen-xcomposite.c
new file mode 100644
index 0000000..5c63ed4
--- /dev/null
+++ b/gl/gloffscreen-xcomposite.c
@@ -0,0 +1,518 @@
+/*
+ * Offscreen OpenGL abstraction layer - GLX specific
+ *
+ * Copyright (c) 2010 Intel Corporation
+ * Authors:
+ *   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 <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include "gloffscreen.h"
+#include "sysemu.h"
+
+static struct GloMain {
+    Display *dpy;
+    int use_ximage;
+} glo;
+static int glo_inited = 0;
+
+struct GloContext {
+    GLuint format_flags;
+    GLXFBConfig fb_config;
+    GLXContext context;
+};
+
+struct GloSurface {
+    GLuint width;
+    GLuint height;
+
+    GloContext *context;
+    Window window;
+    Colormap colormap;
+
+    /* For use by the 'fast' copy code.  */
+    Pixmap pixmap;
+    XImage *image;
+    XShmSegmentInfo shminfo;
+};
+
+int glo_initialised(void)
+{
+    return glo_inited;
+}
+
+/* The X error was disabled, otherwise QEMU might abort.  Printing more error
+ * messages inside below function could help debug potential bugs.  On the
+ * other hand, since the X errors could be caused by the GL calls forwarded
+ * from client OS side, which does not make sense to abort the whole QEMU,
+ * so it is reasonable to redirect error handler here.
+ */
+static int x_errhandler(Display *dpy, XErrorEvent *e)
+{
+    return 0;
+}
+
+/* Sanity test of the host GL capabilities to see whether the gl offscreen
+ * requirements are well supported */
+int glo_sanity_test(void)
+{
+    return 0;
+}
+
+static int glo_can_readback(void)
+{
+    GloContext *context;
+    GloSurface *surface;
+
+#define TX 17
+#define TY 16
+    uint8_t *datain = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *datain_flip = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *dataout = (uint8_t *) g_malloc(4 * TX * TY);
+    uint8_t *p;
+    int x, y, ret = 0;
+
+    const uint32_t buffer_attributes[] = {
+        GLX_RED_SIZE,     8,
+        GLX_GREEN_SIZE,   8,
+        GLX_BLUE_SIZE,    8,
+        GLX_ALPHA_SIZE,   8,
+        GLX_DEPTH_SIZE,   0,
+        GLX_STENCIL_SIZE, 0,
+        0,
+    };
+
+    int buffer_flags = glo_flags_get_from_glx(buffer_attributes, 0);
+    int bpp = glo_flags_get_bytes_per_pixel(buffer_flags);
+    int gl_format, gl_type;
+
+    memset(datain_flip, 0, TX * TY * 4);
+    memset(datain, 0, TX * TY * 4);
+
+    p = datain;
+    for (y = 0; y < TY; y++) {
+        for (x = 0; x < TX; x++) {
+            p[0] = x;
+            p[1] = y;
+            if (bpp > 2) {
+                p[2] = 0;
+            }
+            if (bpp > 3) {
+                p[3] = 0xff;
+            }
+            p += bpp;
+        }
+        memcpy(&datain_flip[((TY - 1) - y) * bpp * TX],
+                        &datain[y * bpp * TX], bpp * TX);
+    }
+
+    context = glo_context_create(buffer_flags, 0);
+    if (!context) {
+        goto done;
+    }
+    surface = glo_surface_create(TX, TY, context);
+    if (!surface) {
+        glo_context_destroy(context);
+        goto done;
+    }
+
+    glo_surface_makecurrent(surface);
+
+    glClear(GL_COLOR_BUFFER_BIT);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0, TX, 0, TY, 0, 1);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glRasterPos2f(0, 0);
+    glo_flags_get_readpixel_type(buffer_flags, &gl_format, &gl_type);
+    glDrawPixels(TX, TY, gl_format, gl_type, datain_flip);
+    glFlush();
+
+    memset(dataout, 0, bpp * TX * TY);
+
+    glo_surface_getcontents(surface, TX * 4, bpp * 8, dataout);
+
+    glo_surface_destroy(surface);
+    glo_context_destroy(context);
+
+    ret = !memcmp(datain, dataout, bpp * TX * TY);
+done:
+    g_free(datain);
+    g_free(datain_flip);
+    g_free(dataout);
+    return ret;
+}
+
+static void glo_test_readback_methods(void)
+{
+    int min, maj;
+
+    glo.use_ximage = 0;
+
+    if (!XCompositeQueryVersion(glo.dpy, &min, &maj)) {
+        return;
+    }
+
+    glo.use_ximage = glo_can_readback();
+}
+
+/* Initialise gloffscreen */
+int glo_init(void)
+{
+    XErrorHandler old_handler;
+
+    if (glo_inited) {
+        return 0;
+    }
+
+    /* Open a connection to the X server */
+    /* TODO: Should we accept a command line switch or an envvar so that
+     * users can give a value different than DISPLAY? */
+    glo.dpy = XOpenDisplay(NULL);
+    if (glo.dpy == NULL) {
+        fprintf(stderr, "vmgl: Unable to open a connection to the X server\n");
+        return -1;
+    }
+
+    /* Safe because we are single threaded. Otherwise we cause recursion
+     * on the next call.  Set the X error handler.  */
+    glo_inited = 1;
+    old_handler = XSetErrorHandler(x_errhandler);
+    glo_test_readback_methods();
+
+    return 0;
+}
+
+/* Uninitialise gloffscreen */
+void glo_kill(void)
+{
+    XCloseDisplay(glo.dpy);
+    glo.dpy = NULL;
+}
+
+/* Like wglGetProcAddress/glxGetProcAddress */
+void *glo_getprocaddress(const char *proc_name)
+{
+    return glXGetProcAddressARB((const GLubyte *) proc_name);
+}
+
+/* Create an OpenGL context for a certain pixel format.
+ * format_flags are made up of the GLO_ constants */
+GloContext *glo_context_create(int format_flags, GloContext *share_lists)
+{
+    GLXFBConfig *fb_configs;
+    int rgba_bits_all;
+    GloContext *context;
+    int rgba_bits[4];
+    int buffer_attributes[] = {
+        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
+        GLX_RED_SIZE,      8,
+        GLX_GREEN_SIZE,    8,
+        GLX_BLUE_SIZE,     8,
+        GLX_ALPHA_SIZE,    8,
+        GLX_DEPTH_SIZE,    0,
+        GLX_STENCIL_SIZE,  0,
+        None
+    };
+
+    /* Set up the surface format from the flags we were given */
+    glo_flags_get_rgba_bits(format_flags, rgba_bits);
+    buffer_attributes[5]  = rgba_bits[0];
+    buffer_attributes[7]  = rgba_bits[1];
+    buffer_attributes[9]  = rgba_bits[2];
+    buffer_attributes[11] = rgba_bits[3];
+    buffer_attributes[13] = glo_flags_get_depth_bits(format_flags);
+    buffer_attributes[15] = glo_flags_get_stencil_bits(format_flags);
+
+    fb_configs = glXChooseFBConfig(glo.dpy, DefaultScreen(glo.dpy),
+                    buffer_attributes, &rgba_bits_all);
+    if (rgba_bits_all == 0) {
+        fprintf(stderr, "vmgl: No matching GLX FB configs found.\n");
+        return NULL;
+    }
+    context = g_malloc0(sizeof(GloContext));
+    context->format_flags = format_flags;
+    context->fb_config = fb_configs[0];
+
+    /* Create a GLX context for OpenGL rendering */
+    context->context = glXCreateNewContext(glo.dpy, context->fb_config,
+                    GLX_RGBA_TYPE, share_lists ? share_lists->context : NULL,
+                    True);
+    if (!context->context) {
+        g_free(context);
+        fprintf(stderr, "vmgl: glXCreateNewContext failed\n");
+        return NULL;
+    }
+
+    return context;
+}
+
+/* Destroy a previously created OpenGL context */
+void glo_context_destroy(GloContext *context)
+{
+    if (!context) {
+        return;
+    }
+
+    /* TODO: check for GloSurfaces using this? */
+    glXDestroyContext(glo.dpy, context->context);
+    g_free(context);
+}
+
+static void glo_surface_free_xshm_image(GloSurface *surface)
+{
+    XShmDetach(glo.dpy, &surface->shminfo);
+    surface->image->data = NULL;
+    XDestroyImage(surface->image);
+    shmdt(surface->shminfo.shmaddr);
+    shmctl(surface->shminfo.shmid, IPC_RMID, NULL);
+}
+
+/* TODO: handle errors */
+static void glo_surface_try_alloc_xshm_image(GloSurface *surface)
+{
+    if (surface->image) {
+        glo_surface_free_xshm_image(surface);
+    }
+
+    surface->image = XShmCreateImage(glo.dpy, DefaultVisual(glo.dpy, 0),
+                    24, ZPixmap, NULL, &surface->shminfo,
+                    surface->width, surface->height);
+
+    surface->shminfo.shmid = shmget(IPC_PRIVATE,
+                    surface->image->bytes_per_line * surface->height,
+                    IPC_CREAT | 0777);
+    surface->shminfo.shmaddr = shmat(surface->shminfo.shmid, NULL, 0);
+    surface->image->data = surface->shminfo.shmaddr;
+    surface->shminfo.readOnly = False;
+    XShmAttach(glo.dpy, &surface->shminfo);
+}
+
+/* Create a surface with given width and height, format_flags are made up
+ * of the GLO_ constants */
+GloSurface *glo_surface_create(int width, int height, GloContext *context)
+{
+    GloSurface *surface;
+    XSetWindowAttributes attr = { 0 };
+    uint32_t mask;
+    XVisualInfo *vis;
+
+    if (!context) {
+        return 0;
+    }
+
+    surface = g_malloc0(sizeof(GloSurface));
+    surface->width = width;
+    surface->height = height;
+    surface->context = context;
+
+    vis = glXGetVisualFromFBConfig(glo.dpy,
+                    ((struct GloContext *) context)->fb_config);
+    surface->colormap = XCreateColormap(glo.dpy, DefaultRootWindow(glo.dpy),
+                    vis->visual, AllocNone);
+
+    attr.background_pixel = 0xff000000;
+    attr.border_pixel = 0;
+    attr.colormap = surface->colormap;
+    attr.event_mask = 0;
+    attr.save_under = True;
+    attr.override_redirect = True;
+    attr.cursor = None;
+    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask |
+            CWOverrideRedirect | CWSaveUnder;
+
+    surface->window = XCreateWindow(glo.dpy, DefaultRootWindow(glo.dpy),
+                    -width - 1000, 0, width, height, 0,
+                    vis->depth, InputOutput, vis->visual, mask, &attr);
+
+    if (!surface->window) {
+        XFreeColormap(glo.dpy, attr.colormap);
+        g_free(surface);
+        fprintf(stderr, "vmgl: XCreateWindow failed\n");
+        return NULL;
+    }
+
+    XMapWindow(glo.dpy, surface->window);
+
+    if (glo.use_ximage) {
+        XCompositeRedirectWindow(glo.dpy, surface->window,
+                        CompositeRedirectAutomatic);
+        surface->pixmap = XCompositeNameWindowPixmap(glo.dpy, surface->window);
+    } else {
+        surface->pixmap = XCreatePixmap(glo.dpy, DefaultRootWindow(glo.dpy),
+                        width, height,
+                        glo_flags_get_bytes_per_pixel(context->format_flags) *
+                        8);
+    }
+
+    if (!surface->pixmap) {
+        XDestroyWindow(glo.dpy, surface->window);
+        XFreeColormap(glo.dpy, attr.colormap);
+        g_free(surface);
+        fprintf(stderr, "vmgl: Failed to allocate pixmap!\n");
+        return NULL;
+    }
+
+    XSync(glo.dpy, 0);
+
+    /* set hints and properties */
+    {
+        XSizeHints sizehints;
+
+        sizehints.x = 0;
+        sizehints.y = 0;
+        sizehints.width = width;
+        sizehints.height = height;
+        sizehints.flags = USSize | USPosition;
+        XSetWMNormalHints(glo.dpy, surface->window, &sizehints);
+        XSetStandardProperties(glo.dpy, surface->window, "", "", None,
+                        NULL, 0, &sizehints);
+
+        XSync(glo.dpy, 0);
+    }
+
+    /* If we're using XImages to pull the data from the graphics card... */
+    glo_surface_try_alloc_xshm_image(surface);
+
+    return surface;
+}
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface)
+{
+    if (surface->pixmap) {
+        XFreePixmap(glo.dpy, surface->pixmap);
+    }
+    XDestroyWindow(glo.dpy, surface->window);
+    XFreeColormap(glo.dpy, surface->colormap);
+    if (surface->image) {
+        glo_surface_free_xshm_image(surface);
+    }
+    g_free(surface);
+}
+
+/* Make the given surface current */
+int glo_surface_makecurrent(GloSurface *surface)
+{
+    int ret;
+
+    if (surface) {
+        ret = glXMakeCurrent(glo.dpy, surface->window,
+                        surface->context->context);
+    } else {
+        ret = glXMakeCurrent(glo.dpy, 0, NULL);
+    }
+
+    return ret;
+}
+
+/* Get the contents of the given surface */
+void glo_surface_getcontents(GloSurface *surface,
+                int stride, int bpp, void *data)
+{
+    static int once;
+    XImage *img;
+
+    if (!surface) {
+        return;
+    }
+
+    if (glo.use_ximage) {
+        glXWaitGL();
+
+        if (surface->image) {
+            XShmGetImage(glo.dpy, surface->pixmap, surface->image,
+                            0, 0, AllPlanes);
+            img = surface->image;
+        } else {
+            img = XGetImage(glo.dpy, surface->pixmap, 0, 0, surface->width,
+                            surface->height, AllPlanes, ZPixmap);
+        }
+
+        if (img) {
+            if (bpp != 32 && bpp != 24 && !once) {
+                fprintf(stderr, "vmgl: Warning: unsupported colourdepth\n");
+                once = 1;
+            }
+
+            if (bpp == img->bits_per_pixel && stride == img->bytes_per_line) {
+                 memcpy(data, img->data, stride * surface->height);
+            } else {
+                int x, y;
+                for (y = 0; y < surface->height; y++) {
+                    for (x = 0; x < surface->width; x++) {
+                        uint8_t *src = ((uint8_t *) img->data) +
+                                x * (img->bits_per_pixel / 8) +
+                                y * img->bytes_per_line;
+                        uint8_t *dst = ((uint8_t *) data) +
+                                x * (bpp / 8) + y * stride;
+                        dst[0] = src[0];
+                        dst[1] = src[1];
+                        dst[2] = src[2];
+                        if (bpp == 32) {
+                            /* When guest is 32 bit and host is 24 */
+                            dst[3] = 0xff;
+                        }
+                    }
+                }
+            }
+
+            /* If we're not using Shm */
+            if (!surface->image) {
+                XDestroyImage(img);
+            }
+
+            return;  /* We're done.  */
+        }
+        /* Uh oh... better fall back.  Perhaps reset glo.use_ximage to 0?  */
+    }
+
+    /* Compatible / fallback method.  */
+    glo_surface_getcontents_readpixels(surface->context->format_flags,
+                    stride, bpp, surface->width, surface->height, data);
+}
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height)
+{
+    if (width) {
+        *width = surface->width;
+    }
+    if (height) {
+        *height = surface->height;
+    }
+}
+
+/* Abstract glXQueryExtensionString() */
+const char *glo_glxqueryextensionsstring(void)
+{
+    return glXQueryExtensionsString(glo.dpy, 0);
+}
diff --git a/gl/gloffscreen.h b/gl/gloffscreen.h
new file mode 100644
index 0000000..3788203
--- /dev/null
+++ b/gl/gloffscreen.h
@@ -0,0 +1,138 @@
+/*
+ * Offscreen OpenGL abstraction layer
+ *
+ * Copyright (c) 2010-2012 Intel Corporation
+ * Authors:
+ *   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 GLOFFSCREEN_H_
+#define GLOFFSCREEN_H_
+
+/* Used to hold data for the OpenGL context */
+typedef struct GloContext GloContext;
+/* Used to hold data for an offscreen surface. */
+typedef struct GloSurface GloSurface;
+
+/* Format flags for glo_surface_create */
+#define GLO_FF_ALPHA_MASK  (0x0001)
+#define GLO_FF_NOALPHA     (0x0000)
+#define GLO_FF_ALPHA       (0x0001)
+
+#define GLO_FF_BITS_MASK   (0x00F0)
+#define GLO_FF_BITS_16     (0x0020)
+#define GLO_FF_BITS_24     (0x0030)
+#define GLO_FF_BITS_32     (0x0040)
+
+#define GLO_FF_DEPTH_MASK   (0x0F00)
+#define GLO_FF_DEPTH_16     (0x0100)
+#define GLO_FF_DEPTH_24     (0x0200)
+#define GLO_FF_DEPTH_32     (0x0300)
+
+#define GLO_FF_STENCIL_MASK   (0xF000)
+#define GLO_FF_STENCIL_8      (0x1000)
+
+/* The only currently supported format */
+#define GLO_FF_DEFAULT     (GLO_FF_BITS_24|GLO_FF_DEPTH_24)
+
+/* Has gloffscreen been previously initialised? */
+int glo_initialised(void);
+
+/* Initialise gloffscreen */
+int glo_init(void);
+
+/* Uninitialise gloffscreen */
+void glo_kill(void);
+
+/* Sanity test of the host GL capabilities to see whether the gl offscreen
+ * requirements are well supported */
+int glo_sanity_test(void);
+
+/* Like glxGetProcAddress/wglGetProcAddress */
+void *glo_getprocaddress(const char *procName);
+
+/* OS-independent glXQueryExtensionsString */
+const char *glo_glxqueryextensionsstring(void);
+
+/* Create an OpenGL context for a certain pixel format. format_flags
+ * are a set of GLO_ constants */
+GloContext *glo_context_create(int format_flags, GloContext *share_lists);
+
+/* Destroy a previouslu created OpenGL context */
+void glo_context_destroy(GloContext *context);
+
+/* Create a surface with given width and height, */
+GloSurface *glo_surface_create(int width, int height, GloContext *context);
+
+/* Destroy the given surface */
+void glo_surface_destroy(GloSurface *surface);
+
+/* Make the given surface current (like glXMakeCurrent) */
+int glo_surface_makecurrent(GloSurface *surface);
+
+/* Get the contents of the given surface. Note that this is top-down, not
+ * bottom-up as glReadPixels would do. */
+void glo_surface_getcontents(GloSurface *surface,
+                int stride, int type, void *data);
+void glo_surface_getcontents_readpixels(int format_flags, int stride, int bpp,
+                int width, int height, void *data);
+
+/* In terms of speed, glReadPixels actually seems the best we can do.
+ * * On Windows PFB_DRAW_TO_BITMAP is software-only.
+ * * http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt would be
+ * useful if we didn't want the data right away (as we could avoid flushing the
+ * pipeline).
+ * * The internal data format seems to be GL_BGRA - and this is indeed faster.
+ * * Apple suggests using GL_UNSIGNED_INT_8_8_8_8_REV instead of
+ * GL_UNSIGNED_BYTE, but there don't appear to be any speed increase from
+ * doing this on Windows at least.
+ */
+
+/* Return the width and height of the given surface */
+void glo_surface_get_size(GloSurface *surface, int *width, int *height);
+
+/* Functions to decode the format flags */
+int glo_flags_get_depth_bits(int format_flags);
+int glo_flags_get_stencil_bits(int format_flags);
+void glo_flags_get_rgba_bits(int format_flags, int *rgba);
+int glo_flags_get_bytes_per_pixel(int format_flags);
+void glo_flags_get_readpixel_type(int format_flags,
+                int *gl_format, int *gl_type);
+
+/* Score how close the given format flags match. 0=great, >0 not so great */
+int glo_flags_score(int format_flags_expected, int format_flags_real);
+
+/* Create a set of format flags from a null-terminated list
+ * of GLX fb_config flags. If assume_booleans is set, items such
+ * as GLX_RGBA/GLX_DOUBLEBUFFER are treated as booleans, not key-value
+ * pairs (glXChooseVisual treats them as booleans, glXChooseFBConfig
+ * as key-value pairs) */
+extern int glo_flags_get_from_glx(const uint32_t *fb_config,
+                int assume_booleans);
+
+/* Use in place of glxGetConfig - returns information from flags based
+ * on a GLX enum */
+uint32_t glo_get_glx_from_flags(int format_flags, int glx_enum);
+
+int glo_acceleration_capability_check(void);
+
+#endif /* GLOFFSCREEN_H_ */
