Enable VSync (Fix bug 5296)
[dana/dcompmgr.git] / glxrender.c
index 511bdb1..5b2d902 100644 (file)
 #include <assert.h>
 #include <stdlib.h>
 
-#include <xcb/glx.h>
-//#include <GL/glext.h>
-//#include <GL/glxext.h>
-#include <GL/glxtokens.h>
+#include <X11/Xmd.h>
+#include <GL/glxproto.h>
+
 #include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glxtokens.h>
+#include <GL/glext.h>
+#include <GL/glxext.h>
 
 #define MAX_DEPTH 32
 
 static int plugin_id;
 
+#define LEFT   0
+#define TOP    1
+#define RIGHT  2
+#define BOTTOM 3
+
+typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *);
+typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int);
+typedef int (*SwapIntervalSGIFunc)(int);
+
 typedef struct {
     void (*screen_paint)(d_screen_t *sc);
     void (*screen_root_pixmap_change)(d_screen_t *sc);
@@ -28,38 +40,54 @@ typedef struct {
     void (*window_resize)(d_window_t *w);
     void (*window_reshape)(d_window_t *w);
 
-    uint16_t shadowalpha;
+    float shadowalpha;
     int xshadowoff;
     int yshadowoff;
 
-    uint32_t fbconfig[MAX_DEPTH + 1];
+    GLXFBConfig fbconfig[MAX_DEPTH + 1];
+
+    GLXContext context;
+    GLuint root_texname;
+    GLXPixmap root_glpixmap;
 
-    xcb_glx_context_t context;
-    xcb_glx_context_tag_t context_tag;
+    BindEXTFunc bind_func;
+    ReleaseEXTFunc release_func;
 } data_t;
 
 typedef struct {
     GLuint texname;
-    xcb_glx_pixmap_t glpixmap;
+    GLXPixmap glpixmap;
+
+    GLfloat *texcoords;
+    GLint *vertices;
+    int nrects;
+
+    xcb_xfixes_fetch_region_cookie_t ck_region;
+    int waiting_region;
+    int x_region;
+    int y_region;
+    int w_region;
+    int h_region;
+    int bw_region;
 } window_data_t;
 
-static uint32_t glxrender_visual_info(uint32_t *props, int vis, int numprops,
-                                      uint32_t name);
-static gboolean glxrender_check_visual(d_screen_t *sc);
 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
 
 static void glxrender_paint(d_screen_t *sc);
 static void glxrender_root_pixmap_change(d_screen_t *sc);
 static void paint_root(d_screen_t *sc, data_t *d);
 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
-                         gboolean opaque, int x, int y, int width,
-                         int height, int bwidth);
-static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
-                         int x, int y, int width, int height, int bwidth);
+                         int x, int y, GLfloat z);
+static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
+                         GLfloat z);
 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
                                            window_data_t *wd);
+static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
+static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
                                          window_data_t *wd);
+static void glxrender_free_window_region(window_data_t *wd);
+static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
 
 static void glxrender_window_show(d_window_t *window);
@@ -70,14 +98,18 @@ static void glxrender_window_reshape(d_window_t *window);
 void
 glxrender_init(d_screen_t *sc, int id)
 {
-    xcb_void_cookie_t ck;
-    xcb_generic_error_t *err;
-    xcb_glx_make_current_cookie_t curck;
-    xcb_glx_make_current_reply_t *currep;
+    static int context_visual_config[] = {
+        GLX_DEPTH_SIZE, 1,
+        GLX_DOUBLEBUFFER,
+        GLX_RGBA,
+        XCB_NONE
+    };
+    XVisualInfo *vi;
+    data_t *d;
 
     plugin_id = id;
 
-    data_t *d = malloc(sizeof(data_t));
+    d = malloc(sizeof(data_t));
     d->screen_paint = sc->screen_paint;
     d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
     d->window_show = sc->window_show;
@@ -93,12 +125,13 @@ glxrender_init(d_screen_t *sc, int id)
     sc->window_resize = glxrender_window_resize;
     sc->window_reshape = glxrender_window_reshape;
 
-    d->shadowalpha = 0x3333; /* 20% */
+    d->shadowalpha = 0.2f; /* 20% */
     d->xshadowoff = 2;
     d->yshadowoff = 2;
 
-    if (!glxrender_check_visual(sc)) {
-        printf("unable to use the overlay window for GLX\n");
+    vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
+    if (!vi) {
+        printf("unable to find a valid double buffered GL context to use\n");
         exit(1);
     }
 
@@ -107,292 +140,127 @@ glxrender_init(d_screen_t *sc, int id)
         exit(1);
     }
 
-    d->context = xcb_generate_id(sc->dpy->conn);
-    ck = xcb_glx_create_context_checked(sc->dpy->conn, d->context,
-                                        sc->overlay_visual, sc->num,
-                                        XCB_NONE, TRUE);
-    if ((err = xcb_request_check(sc->dpy->conn, ck))) {
-        printf("context creation failed\n");
-        display_error(sc->dpy, err);
-        free(err);
-        exit(1);
-    }
-
-    curck = xcb_glx_make_current(sc->dpy->conn,
-                                 sc->overlay, d->context, XCB_NONE);
-    currep = xcb_glx_make_current_reply(sc->dpy->conn, curck, &err);
-    if (!currep) {
-        if (err) {
-            display_error(sc->dpy, err);
-            free(err);
-        }
-        printf("make current failed\n");
-        exit(1);
-    }
-    d->context_tag = currep->context_tag;
-    free(currep);
+    d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
+    glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
 
     glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
-    glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels,
-            0.0, -1.0, 100.0);
+    glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
+            -100.0, 100.0);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
-    glClear(GL_COLOR_BUFFER_BIT);
     glEnable(GL_TEXTURE_2D);
-    xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
-    glClearColor(0.4, 0.4, 0.4, 1.0);
+    glEnable(GL_DEPTH_TEST);
+    //glEnable(GL_SCISSOR_TEST); ?? what is this, glxcompmgr enables it
+    //glEnable(GL_STENCIL_TEST); ?? what is this, glxcompmgr enables it
 
-/*
-  glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);                          
-  glEnable(GL_BLEND);
-*/
-}
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_BLEND);
 
-static uint32_t
-glxrender_visual_info(uint32_t *props, int vis, int numprops, uint32_t name)
-{
-    int s;
-
-    assert(numprops > 14);
-
-    /*
-    for (s = vis * numprops; s < vis*numprops + numprops; ++s)
-        printf("%x ", props[s]);
-    printf("\n");
-    */
-
-    s = vis * numprops;
-    switch (name) {
-    case GLX_VISUAL_ID:     return props[s+0];  /* id number */
-    case GLX_X_VISUAL_TYPE: return props[s+1];  /* XCB_CLASS_TRUE_COLOR etc */
-    case GLX_USE_GL:        return props[s+2];  /* boolean */
-    case GLX_RED_SIZE:      return props[s+3];  /* number */
-    case GLX_GREEN_SIZE:    return props[s+4];  /* number */
-    case GLX_BLUE_SIZE:     return props[s+5];  /* number */
-    case GLX_ALPHA_SIZE:    return props[s+6];  /* number */
-    case GLX_DOUBLEBUFFER:  return props[s+11]; /* boolean */
-    case GLX_DEPTH_SIZE:    return props[s+14]; /* number */
-    case GLX_STENCIL_SIZE:  return props[s+15]; /* number */
-    default: assert(0);
-    }
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
+
+    d->bind_func = (BindEXTFunc)
+        glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
+    d->release_func = (ReleaseEXTFunc)
+        glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
+
+    SwapIntervalSGIFunc swap_interval_func = (SwapIntervalSGIFunc)
+        glXGetProcAddress((const guchar*)"glXSwapIntervalSGI");
+    if(swap_interval_func)
+        swap_interval_func(1);
+
+    glGenTextures(1, &d->root_texname);
+    d->root_glpixmap = XCB_NONE;
 }
 
 static gboolean
-glxrender_check_visual(d_screen_t *sc)
+glxrender_find_fb_config(d_screen_t *sc, data_t *d)
 {
-    xcb_glx_get_visual_configs_cookie_t ck;
-    xcb_glx_get_visual_configs_reply_t *rep;
-    gboolean ok = FALSE;
-
-    ck = xcb_glx_get_visual_configs_unchecked(sc->dpy->conn, sc->num);
-    rep = xcb_glx_get_visual_configs_reply(sc->dpy->conn, ck, NULL);
-    if (rep) {
-        uint32_t *props;
-        unsigned int i, nprops;
-
-/*
-        static int config[] = {
-            GLX_DEPTH_SIZE, 1,
-            GLX_DOUBLEBUFFER,
-            GLX_RGBA,
-            XCB_NONE
-        };
-*/
-
-        props = xcb_glx_get_visual_configs_property_list(rep);
-        nprops = rep->num_properties;
+    static const int drawable_tfp_attrs[] = {
+        GLX_CONFIG_CAVEAT, GLX_NONE,
+        GLX_DOUBLEBUFFER, FALSE,
+        GLX_DEPTH_SIZE, 0,
+        GLX_RED_SIZE, 1,
+        GLX_GREEN_SIZE, 1,
+        GLX_BLUE_SIZE, 1,
+        GLX_ALPHA_SIZE, 1,
+        GLX_RENDER_TYPE, GLX_RGBA_BIT,
+        GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
+        XCB_NONE
+    };
+    int db, stencil, depth, numfb, i;
+    GLXFBConfig *fbcons;
+    XVisualInfo tvis, *visinfo;
 
-        for (i = 0; i < rep->num_visuals; ++i) {
-            /* look for the overlay's visual */
-            if (glxrender_visual_info(props, i, nprops, GLX_VISUAL_ID) !=
-                sc->overlay_visual)
-            {
-                continue;
-            }
+    fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
+                               drawable_tfp_attrs, &numfb);
+    if (!fbcons) return FALSE;
 
-            if (!glxrender_visual_info(props, i, nprops, GLX_USE_GL)) {
-                printf("overlay visual does not support GL\n");
-                break;
-            }
+    for (i = 0; i <= MAX_DEPTH; i++) {
+        int j, count, value;
+        VisualID vid;
 
-            if (!glxrender_visual_info(props, i, nprops, GLX_DOUBLEBUFFER)) {
-                printf("overlay visual is not double buffered\n");
-                break;
-            }
+        vid = 0;
+        d->fbconfig[i] = 0;
+        db = 32767;
+        stencil = 32767;
+        depth = 32767;
 
-            ok = TRUE; /* yippa ! */
-        }
+        //printf("looking for depth %d\n", i);
 
-        free(rep);
-    }
-    return ok;
-}
+        tvis.depth = i;
+        visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
+                                 &tvis, &count);
+        /* pick the nicest visual for the depth */
+        for (j = 0; j < count; j++) {
+            glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
+            if (!value)
+                continue;
 
-static uint32_t
-glxrender_fbconfig_info(uint32_t *props, int con, int numprops, uint32_t name)
-{
-    int i;
+            glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
+                         &value);
+            if (value > db)
+                continue;
+            db = value;
 
-    for (i = 0; i < numprops; ++i) {
-        if (props[i*2 + con*numprops*2] == name)
-            return props[i*2 + con*numprops*2 + 1];
-    }
-    return 0;
-}
+            glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
+                         &value);
+            if (value > stencil)
+                continue;
+            stencil = value;
 
-static gboolean
-glxrender_find_fb_config(d_screen_t *sc, data_t *d)
-{
-    xcb_glx_get_visual_configs_cookie_t vck;
-    xcb_glx_get_visual_configs_reply_t *vrep;
-    xcb_glx_get_fb_configs_cookie_t fbck;
-    xcb_glx_get_fb_configs_reply_t *fbrep;
-    xcb_depth_iterator_t depth_it;
-    unsigned int i, nvprops, nfbprops;
-    uint32_t *vprops, *fbprops;
-    uint32_t db, stencil, depthsize;
-
-    vck = xcb_glx_get_visual_configs_unchecked(sc->dpy->conn, sc->num);
-    vrep = xcb_glx_get_visual_configs_reply(sc->dpy->conn, vck, NULL);
-    if (!vrep) return FALSE;
-
-    fbck = xcb_glx_get_fb_configs(sc->dpy->conn, sc->num);
-    fbrep = xcb_glx_get_fb_configs_reply(sc->dpy->conn, fbck, NULL);
-    if (!fbrep) return FALSE;
-
-    vprops = xcb_glx_get_visual_configs_property_list(vrep);
-    nvprops = vrep->num_properties;
-    fbprops = xcb_glx_get_fb_configs_property_list(fbrep);
-    nfbprops = fbrep->num_properties;
-
-    memset(d->fbconfig, 0, (MAX_DEPTH + 1) * sizeof(d->fbconfig[0]));
-
-    db = 32767;
-    stencil = 32767;
-    depthsize = 32767;
-    depth_it = xcb_screen_allowed_depths_iterator(sc->super);
-    for (; depth_it.rem; xcb_depth_next(&depth_it)) {
-        uint32_t vid;
-        int j;
-        unsigned int k;
-        xcb_visualtype_t *visuals;
-        int nvisuals;
+            glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
+                         &value);
+            if (value > depth)
+                continue;
+            depth = value;
 
-        vid = 0;
-        if (depth_it.data->depth > MAX_DEPTH) continue;
+            /* use this visual */
+            vid = visinfo[j].visualid;
+        }
 
-        printf("looking for depth %d\n", depth_it.data->depth);
+        if (!vid) continue;
 
-        visuals = xcb_depth_visuals(depth_it.data);
-        nvisuals = xcb_depth_visuals_length(depth_it.data);
+        /* look for an fbconfig for this visual */
+        for (j = 0; j < numfb; ++j) {
+            glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
+                                 GLX_VISUAL_ID, &value);
+            if ((unsigned)value == vid) {
+                d->fbconfig[i] = fbcons[j];
 
-        /* pick the nicest visual for the depth */
-        for (j = 0; j < nvisuals; ++j) {
-            uint32_t val;
-
-            /* find the visual's properties */
-            for (k = 0; k < vrep->num_visuals; ++k)
-                if (glxrender_visual_info(vprops, k, nvprops, GLX_VISUAL_ID)
-                    == visuals[j].visual_id)
-                {
-                    break;
-                }
-            if (k == vrep->num_visuals) continue;
-
-            val = glxrender_visual_info(vprops, k, nvprops, GLX_USE_GL);
-            if (!val) continue;
-
-            val = glxrender_visual_info(vprops, k, nvprops, GLX_DOUBLEBUFFER);
-            if (!val > db) continue;
-            db = val;
-
-            val = glxrender_visual_info(vprops, k, nvprops, GLX_STENCIL_SIZE);
-            if (!val > stencil) continue;
-            stencil = val;
-
-            val = glxrender_visual_info(vprops, k, nvprops, GLX_DEPTH_SIZE);
-            if (!val > depthsize) continue;
-            depthsize = val;
-
-            /* try this visual */
-            vid = visuals[j].visual_id;
-
-            /* look for an fbconfig for this visual */
-            for (k = 0; k < fbrep->num_FB_configs; ++k) {
-                uint32_t val;
-
-                //printf("root visual 0x%x\n", sc->super.root_visual);
-                //printf("overlay visual 0x%x\n", sc->overlay_visual);
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_VISUAL_ID);
-                //printf("x visual 0x%x\n", val);
-                if (val != vid) continue;
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_BIND_TO_TEXTURE_TARGETS_EXT);
-                printf("BIND TO TARGETS %x\n", val);
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_DOUBLEBUFFER);
-                printf("dbl buffer %s\n", val ? "yes" : "no");
-                if (val) continue;
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_DEPTH_SIZE);
-                printf("depth size %d\n", val);
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_RED_SIZE);
-                printf("red size %d\n", val);
-                if (!val) continue;
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_GREEN_SIZE);
-                printf("green size %d\n", val);
-                if (!val) continue;
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_BLUE_SIZE);
-                printf("blue size %d\n", val);
-                if (!val) continue;
-
-                val = glxrender_fbconfig_info(fbprops, k, nfbprops,
-                                              GLX_ALPHA_SIZE);
-                printf("alpha size %d\n", val);
-                //if (depth_it.data->depth == 32 && !val) continue;
-
-                val = glxrender_fbconfig_info(fbprops, j, nfbprops,
-                                              GLX_RENDER_TYPE);
-                printf("rgba bit %s\n", val & GLX_RGBA_BIT ? "yes" : "no");
-                if (!(val & GLX_RGBA_BIT)) continue;
-
-                val = glxrender_fbconfig_info(fbprops, j, nfbprops,
-                                              GLX_CONFIG_CAVEAT);
-                printf("caveat 0x%x\n", val);
-
-                val = glxrender_fbconfig_info(fbprops, j, nfbprops,
-                                              GLX_BIND_TO_TEXTURE_RGBA_EXT);
-                printf("bind ext %s\n", val ? "yes" : "no");
-                if (!val) continue;
-
-                d->fbconfig[depth_it.data->depth] =
-                    glxrender_fbconfig_info(fbprops, i, nfbprops,
-                                            GLX_FBCONFIG_ID);
+                printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
+                       (uint32_t)vid, (uint32_t)fbcons[j], i);
                 break;
             }
-
-            if (d->fbconfig[depth_it.data->depth])
-                printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
-                       vid, d->fbconfig[depth_it.data->depth],
-                       depth_it.data->depth);
         }
     }
 
-    free(vrep);
-    free(fbrep);
+    XFree(fbcons);
     return TRUE;
 }
 
@@ -400,7 +268,11 @@ void
 glxrender_free(d_screen_t *sc)
 {
     data_t *d = screen_find_plugin_data(sc, plugin_id);
-    free(d);
+    if (d) {
+        glxrender_free_root_pixmap(sc, d);
+        glXDestroyContext(sc->dpy->xlib_dpy, d->context);
+        free(d);
+    }
     screen_remove_plugin_data(sc, plugin_id);
 }
 
@@ -422,6 +294,7 @@ void
 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
 {
     glxrender_free_window_pixmap(w, d, wd);
+    glxrender_free_window_region(wd);
     glDeleteTextures(1, &wd->texname);
     free(wd);
 }
@@ -438,14 +311,22 @@ glxrender_window_show(d_window_t *w)
     d->window_show(w);
 
     wd = window_find_plugin_data(w, plugin_id);
-    if (wd)
+    if (wd) {
         glxrender_window_free_data(w, d, wd);
-   
+        window_remove_plugin_data(w, plugin_id);
+    }
+
     wd = malloc(sizeof(window_data_t));
     glGenTextures(1, &wd->texname);
     wd->glpixmap = XCB_NONE;
+    wd->texcoords = NULL;
+    wd->vertices = NULL;
+    wd->nrects = 0;
+    wd->waiting_region = FALSE;
 
     window_add_plugin_data(w, plugin_id, wd);
+
+    glxrender_fetch_window_region(w, wd);
 }
 
 static void
@@ -471,33 +352,40 @@ glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
     /* this might cause an error, oh well */
     if (wd->glpixmap) {
         glBindTexture(GL_TEXTURE_2D, wd->texname);
+        d->release_func(w->sc->dpy->xlib_dpy,
+                        wd->glpixmap, GLX_FRONT_LEFT_EXT);
+        glBindTexture(GL_TEXTURE_2D, 0);
 
-        {
-            /*
-              ReleaseTexImageEXT
-              1           CARD8           opcode (X assigned)
-              1           16              GLX opcode (glXVendorPrivate)
-              2           5               request length
-              4           1331            vendor specific opcode
-              4           CARD32          context tag
-              4           GLX_DRAWABLE    drawable
-              4           INT32           buffer
-            */
-            unsigned int len = (2 + 0) * sizeof(uint32_t);
-            uint32_t data[] = {
-                wd->glpixmap,
-                GLX_FRONT_LEFT_EXT
-            };
-            xcb_glx_vendor_private(w->sc->dpy->conn,
-                                   1331,
-                                   d->context_tag,
-                                   len, (uint8_t*)data);
-        }
+        glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
+        wd->glpixmap = XCB_NONE;
+
+    }
+}
+
+static void
+glxrender_free_window_region(window_data_t *wd)
+{
+    if (wd->nrects) {
+        free(wd->texcoords);
+        free(wd->vertices);
+        wd->texcoords = NULL;
+        wd->vertices = NULL;
+        wd->nrects = 0;
+    }
+}
 
+static void
+glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
+{
+    /* this might cause an error, oh well */
+    if (d->root_glpixmap) {
+        glBindTexture(GL_TEXTURE_2D, d->root_texname);
+        d->release_func(sc->dpy->xlib_dpy,
+                        d->root_glpixmap, GLX_FRONT_LEFT_EXT);
         glBindTexture(GL_TEXTURE_2D, 0);
 
-        xcb_glx_destroy_glx_pixmap(w->sc->dpy->conn, wd->glpixmap);
-        wd->glpixmap = XCB_NONE;
+        glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
+        d->root_glpixmap = XCB_NONE;
     }
 }
 
@@ -507,79 +395,189 @@ glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
     xcb_pixmap_t px;
     uint8_t depth;
 
-    static const uint32_t attrs[] = {
+    static int attrs[] = {
         GLX_TEXTURE_FORMAT_EXT,
-        GLX_TEXTURE_FORMAT_RGBA_EXT
+        XCB_NONE,
+        XCB_NONE
     };
 
     px = window_get_pixmap(w);
     depth = window_get_depth(w);
-    if (px && d->fbconfig[depth]) {
-        wd->glpixmap = xcb_generate_id(w->sc->dpy->conn);
-        printf("creating pixmap fbcon 0x%x\n", d->fbconfig[depth]);
-
-        xcb_void_cookie_t ck =
-            xcb_glx_create_pixmap_checked(w->sc->dpy->conn, w->sc->num,
-                                          d->fbconfig[depth],
-                                          px, wd->glpixmap,
-                                          sizeof(attrs)/sizeof(attrs[0]),
-                                          attrs);
-        {
-            xcb_generic_error_t *err;
-            err = xcb_request_check(w->sc->dpy->conn, ck);
-            if (err) {
-                printf("error creating pixmap\n");
-                display_error(w->sc->dpy, err);
-                free(err);
-            }
-        }
 
-        glBindTexture(GL_TEXTURE_2D, wd->texname);
+    if (!px) return;
 
-        {
-            /*
-              BindTexImageEXT
-              1           CARD8                   opcode (X assigned)
-              1           16                      GLX opcode (glXVendorPrivate)
-              2           6+n                     request length
-              4           1330                    vendor specific opcode
-              4           CARD32                  context tag
-              4           GLX_DRAWABLE            drawable
-              4           INT32                   buffer
-              4           CARD32                  num_attributes
-              4*n         LISTofATTRIBUTE_PAIR    attribute, value pairs.
-            */
-            unsigned int len = (3 + 0) * sizeof(uint32_t);
-            uint32_t data[] = {
-                wd->glpixmap,
-                GLX_FRONT_LEFT_EXT,
-                0
-            };
-            xcb_glx_vendor_private(w->sc->dpy->conn,
-                                   1330,
-                                   d->context_tag,
-                                   len, (uint8_t*)data);
-        }
+    if (!d->fbconfig[depth]) {
+        printf("no GL visual for depth %d\n", depth);
+        return;
+    }
 
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    if (window_is_argb(w))
+        attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
+    else
+        attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
+
+    wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
+                                   d->fbconfig[depth],
+                                   px, attrs);
+#if 0
+    wd->glpixmap = xcb_generate_id(w->sc->dpy->conn);
+    int v;
+    glXGetFBConfigAttrib(w->sc->dpy->xlib_dpy, d->fbconfig[depth],
+                         GLX_FBCONFIG_ID, &v);
+    xcb_void_cookie_t ck =
+        xcb_glx_create_pixmap_checked(w->sc->dpy->conn, w->sc->num,
+                                      v,
+                                      px, wd->glpixmap,
+                                      2,
+                                      attrs);
+    xcb_generic_error_t *err = xcb_request_check(w->sc->dpy->conn, ck);
+    if (err) {
+        display_error(w->sc->dpy, err);
+        free(err);
+        wd->glpixmap = XCB_NONE;
+        return;
+    }
+#endif
 
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    glBindTexture(GL_TEXTURE_2D, wd->texname);
+    d->bind_func(w->sc->dpy->xlib_dpy,
+                 wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
+#if 0
+    {
+        /*
+          BindTexImageEXT
+          1           CARD8                   opcode (X assigned)
+          1           16                      GLX opcode (glXVendorPrivate)
+          2           6+n                     request length
+          4           1330                    vendor specific opcode
+          4           CARD32                  context tag
+          4           GLX_DRAWABLE            drawable
+          4           INT32                   buffer
+          4           CARD32                  num_attributes
+          4*n         LISTofATTRIBUTE_PAIR    attribute, value pairs.
+        */
+        unsigned int len = 12;
+        uint32_t data[] = {
+            wd->glpixmap,
+            GLX_FRONT_LEFT_EXT,
+            0,
+        };
+        xcb_glx_vendor_private(w->sc->dpy->conn,
+                               X_GLXvop_BindTexImageEXT,
+                               1,
+                               len, (uint8_t*)data);
+    }
+#endif
 
-        glBindTexture(GL_TEXTURE_2D, 0);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+static void
+glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
+{
+    window_get_area(w, &wd->x_region, &wd->y_region,
+                    &wd->w_region, &wd->h_region, &wd->bw_region);
+
+    wd->ck_region =
+        xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
+                                          window_get_region(w));
+    wd->waiting_region = TRUE;
+    xcb_flush(w->sc->dpy->conn);
+}
+
+static void
+glxrender_update_window_region(d_window_t *w, window_data_t *wd)
+{
+    xcb_xfixes_fetch_region_reply_t *rep;
+    xcb_rectangle_t area, *rects;
+    int nrects, i, j;
+
+    if (!wd->waiting_region) return;
+
+    area.x = wd->x_region;
+    area.y = wd->y_region;
+    area.width = wd->w_region + wd->bw_region * 2;
+    area.height = wd->h_region + wd->bw_region * 2;
+
+    rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
+    if (!rep) {
+        rects = &area;
+        nrects = 1;
     }
+    else {
+        rects = xcb_xfixes_fetch_region_rectangles(rep);
+        nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
+    }
+
+    wd->texcoords = (GLfloat*)realloc(wd->texcoords,
+                                      sizeof(GLfloat) * (nrects * 4));
+    wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
+    wd->nrects = nrects;
+
+    for (i = j = 0; i < nrects * 4; ++j, i += 4) {
+        wd->texcoords[i+LEFT] =
+            (GLfloat)(rects[j].x - area.x) / (GLfloat)area.width;
+        wd->texcoords[i+TOP] =
+            (GLfloat)(rects[j].y - area.y) / (GLfloat)area.height;
+        wd->texcoords[i+RIGHT] =
+            (GLfloat)(rects[j].x - area.x + rects[j].width) /
+            (GLfloat)area.width;
+        wd->texcoords[i+BOTTOM] =
+            (GLfloat)(rects[j].y - area.y + rects[j].height) /
+            (GLfloat)area.height;
+
+        wd->vertices[i+LEFT] = rects[j].x - area.x;
+        wd->vertices[i+TOP] = rects[j].y - area.y;
+        wd->vertices[i+RIGHT] = rects[j].x - area.x + rects[j].width;
+        wd->vertices[i+BOTTOM] = rects[j].y - area.y + rects[j].height;
+    }
+
+    if (rep)
+        free(rep);
+
+    wd->waiting_region = FALSE;
 }
 
 static void
 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
 {
     xcb_pixmap_t px;
+    static int attrs[] = {
+        GLX_TEXTURE_FORMAT_EXT,
+        GLX_TEXTURE_FORMAT_RGB_EXT,
+        XCB_NONE
+    };
 
     px = screen_get_root_pixmap(sc);
-    if (px) {
+    if (!px) return;
+
+    if (!d->fbconfig[sc->super->root_depth]) {
+        printf("no GL visual for depth %d\n", sc->super->root_depth);
+        return;
     }
+
+    d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
+                                       d->fbconfig[sc->super->root_depth],
+                                       px, attrs);
+
+
+    glBindTexture(GL_TEXTURE_2D, d->root_texname);
+    d->bind_func(sc->dpy->xlib_dpy,
+                 d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
 }
 
 static void
@@ -596,6 +594,7 @@ glxrender_window_resize(d_window_t *w)
 
     assert(wd != NULL);
     glxrender_free_window_pixmap(w, d, wd);
+    glxrender_fetch_window_region(w, wd);
 }
 
 static void
@@ -611,7 +610,8 @@ glxrender_window_reshape(d_window_t *w)
     d->window_reshape(w);
 
     assert(wd != NULL);
-    glxrender_free_window_pixmap(w, d, wd);
+    //glxrender_free_window_pixmap(w, d, wd);
+    glxrender_fetch_window_region(w, wd);
 }
 
 static void
@@ -620,11 +620,7 @@ glxrender_root_pixmap_change(d_screen_t *sc)
     data_t *d;
 
     d = screen_find_plugin_data(sc, plugin_id);
-    int a; /* XXX free things here */
-    //if (d->root_picture) {
-    //    xcb_render_free_picture(sc->dpy->conn, d->root_picture);
-    //    d->root_picture = XCB_NONE;
-    //}
+    glxrender_free_root_pixmap(sc, d);
 
     /* pass it on */
     d->screen_root_pixmap_change(sc);
@@ -635,11 +631,55 @@ glxrender_paint(d_screen_t *sc)
 {
     data_t *d = screen_find_plugin_data(sc, plugin_id);
     d_list_it_t *it;
+    GLfloat z;
 
     //printf("painting\n");
 
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    /* add 0.1f to keep everything above the root */
+    z = list_length(sc->stacking) * 0.1f + 0.1f;
+    for (it = list_top(sc->stacking); it; it = it->next) {
+        d_window_t *w = it->data;
+
+        if (!window_is_input_only(w) &&
+            (window_is_mapped(w) || window_is_zombie(w)))
+        {
+            int x, y, width, height, bwidth;
+            gboolean opaque;
+            window_data_t *wd;
+
+            window_get_area(w, &x, &y, &width, &height, &bwidth);
+
+            if (!(x < sc->super->width_in_pixels &&
+                  y < sc->super->height_in_pixels &&
+                  (x + width > 0 || x + width + d->xshadowoff > 0) &&
+                  (y + height > 0 || y + height + d->yshadowoff > 0)))
+            {
+                continue;
+            }
+
+            opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
+
+            if (opaque) {
+                wd = window_find_plugin_data(w, plugin_id);
+
+                //glPushMatrix();
+
+                paint_window(w, d, wd, x, y, z - 0.05f);
+
+                //glPopMatrix();
+            }
+
+            z -= 0.1f;
+        }
+    }
+
     paint_root(sc, d);
 
+    glEnable(GL_BLEND);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
     for (it = list_bottom(sc->stacking); it; it = it->prev) {
         d_window_t *w = it->data;
 
@@ -649,6 +689,8 @@ glxrender_paint(d_screen_t *sc)
             int x, y, width, height, bwidth;
             gboolean opaque;
             window_data_t *wd;
+            uint16_t opac;
+            GLfloat alpha;
 
             window_get_area(w, &x, &y, &width, &height, &bwidth);
 
@@ -660,16 +702,36 @@ glxrender_paint(d_screen_t *sc)
                 continue;
             }
 
-            opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
+            opac = window_get_opacity(w);
+            opaque = !window_is_argb(w) && opac == 0xffff;
 
             wd = window_find_plugin_data(w, plugin_id);
 
-            paint_shadow(w, d, wd, x, y, width, height, bwidth);
-            paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
+            /* black shadow */
+            alpha = d->shadowalpha;
+            alpha *= opac;
+            alpha /= 0xffff;
+            if (alpha >= 0.01) {
+                glColor4f(0.0f, 0.0f, 0.0f, alpha);
+                paint_shadow(d, wd, x, y, z);
+            }
+
+            if (!opaque) {
+                glColor4us(opac, opac, opac, opac);
+                paint_window(w, d, wd, x, y, z + 0.05f);
+            }
+
+            z += 0.1f;
         }
     }
 
-    xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
+    glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+    glDisable(GL_BLEND);
+
+    glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
+
+    glFinish();
 
     /* call the function we replaced in the chain */
     d->screen_paint(sc);
@@ -678,46 +740,80 @@ glxrender_paint(d_screen_t *sc)
 static void
 paint_root(d_screen_t *sc, data_t *d)
 {
-    //if (!d->root_picture)
-    glxrender_update_root_pixmap(sc, d);
+    if (!d->root_glpixmap)
+        glxrender_update_root_pixmap(sc, d);
+
+    glBindTexture(GL_TEXTURE_2D, d->root_texname);
+    glBegin(GL_QUADS);
+    glTexCoord2f(0, 0);
+    glVertex3i(0, 0, 0);
+    glTexCoord2f(1, 0);
+    glVertex3i(sc->super->width_in_pixels, 0, 0);
+    glTexCoord2f(1, 1);
+    glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
+    glTexCoord2f(0, 1);
+    glVertex3i(0, sc->super->height_in_pixels, 0);
+    glEnd();
 
-    glClear(GL_COLOR_BUFFER_BIT);
+    glBindTexture(GL_TEXTURE_2D, 0);
 }
 
 static void
-paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
-             int x, int y, int width, int height, int bwidth)
+paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
+             GLfloat z)
 {
+    int i;
+
     if (!wd->glpixmap)
         glxrender_update_window_pixmap(w, d, wd);
+    if (wd->waiting_region)
+        glxrender_update_window_region(w, wd);
+
+    if (wd->nrects < 1) return;
 
     glBindTexture(GL_TEXTURE_2D, wd->texname);
+
     glBegin(GL_QUADS);
-    glColor3f(1.0, 1.0, 1.0);
-    glVertex2i(x, y);
-    glTexCoord2f(1, 0);
-    glVertex2i(x + width + bwidth, y);
-    glTexCoord2f(1, 1);
-    glVertex2i(x + width + bwidth,
-               y + height + bwidth);
-    glTexCoord2f(0, 1);
-    glVertex2i(x, y + height + bwidth);
-    glTexCoord2f(0, 0);
+    for (i = 0; i < wd->nrects * 4; i += 4) {
+        glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
+        glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
+        glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
+        glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
+        glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
+        glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
+        glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
+        glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
+    }
     glEnd();
+
+    glBindTexture(GL_TEXTURE_2D, 0);
 }
 
 static void
-paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
-             int x, int y, int width, int height, int bwidth)
+paint_shadow(data_t *d, window_data_t *wd, int x, int y, GLfloat z)
 {
-/*
-    xcb_render_composite(w->sc->dpy->conn,
-                         XCB_RENDER_PICT_OP_OVER,
-                         wd->shadow_picture,
-                         wd->picture,
-                         d->overlay_buffer,
-                         0, 0, 0, 0,
-                         x+d->xshadowoff, y+d->yshadowoff,
-                         width + bwidth*2, height + bwidth *2);
-*/
+    int i;
+
+    if (wd->nrects < 1) return;
+
+    /* shape the shadow to the window */
+    glBindTexture(GL_TEXTURE_2D, wd->texname);
+
+    x += d->xshadowoff;
+    y += d->yshadowoff;
+
+    glBegin(GL_QUADS);
+    for (i = 0; i < wd->nrects * 4; i += 4) {
+        glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
+        glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
+        glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
+        glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
+        glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
+        glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
+        glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
+        glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
+    }
+    glEnd();
+
+    glBindTexture(GL_TEXTURE_2D, 0);
 }