i've reimplemented glXChooseFBConfig for xcb
authorDana Jansens <danakj@orodu.net>
Tue, 11 Mar 2008 04:47:12 +0000 (00:47 -0400)
committerDana Jansens <danakj@orodu.net>
Tue, 11 Mar 2008 04:47:12 +0000 (00:47 -0400)
glxcompat.c [new file with mode: 0644]
glxcompat.h [new file with mode: 0644]
glxrender.c
screen.c

diff --git a/glxcompat.c b/glxcompat.c
new file mode 100644 (file)
index 0000000..61cd93b
--- /dev/null
@@ -0,0 +1,398 @@
+#include "efence.h"
+
+#include "glxcompat.h"
+#include <xcb/glx.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <GL/glxtokens.h>
+#include <glib.h>
+
+static uint32_t*
+code_to_ptr(d_glx_fb_config_t *fb, uint32_t code)
+{
+    if (code == GLX_FBCONFIG_ID)  return &fb->fbconfig_id;
+    if (code == GLX_BUFFER_SIZE)  return &fb->buffer_size;
+    if (code == GLX_LEVEL)        return &fb->level;
+    if (code == GLX_DOUBLEBUFFER) return &fb->doublebuffer;
+    if (code == GLX_STEREO)       return &fb->stereo;
+    if (code == GLX_AUX_BUFFERS)  return &fb->aux_buffers;
+    if (code == GLX_RED_SIZE)     return &fb->red_size;
+    if (code == GLX_GREEN_SIZE)   return &fb->green_size;
+    if (code == GLX_BLUE_SIZE)    return &fb->blue_size;
+    if (code == GLX_ALPHA_SIZE)   return &fb->alpha_size;
+    if (code == GLX_DEPTH_SIZE)   return &fb->depth_size;
+    if (code == GLX_STENCIL_SIZE)     return &fb->stencil_size;
+    if (code == GLX_ACCUM_RED_SIZE)   return &fb->accum_red_size;
+    if (code == GLX_ACCUM_GREEN_SIZE) return &fb->accum_green_size;
+    if (code == GLX_ACCUM_BLUE_SIZE)  return &fb->accum_blue_size;
+    if (code == GLX_ACCUM_ALPHA_SIZE) return &fb->accum_alpha_size;
+    if (code == GLX_RENDER_TYPE)      return &fb->render_type;
+    if (code == GLX_DRAWABLE_TYPE)    return &fb->drawable_type;
+    if (code == GLX_X_RENDERABLE)     return &fb->x_renderable;
+    if (code == GLX_X_VISUAL_TYPE)    return &fb->x_visual_type;
+    if (code == GLX_CONFIG_CAVEAT)    return &fb->config_caveat;
+    if (code == GLX_TRANSPARENT_TYPE) return &fb->transparent_type;
+    if (code == GLX_TRANSPARENT_INDEX_VALUE)
+        return &fb->transparent_index_value;
+    if (code == GLX_TRANSPARENT_RED_VALUE)
+        return &fb->transparent_red_value;
+    if (code == GLX_TRANSPARENT_GREEN_VALUE)
+        return &fb->transparent_green_value;
+    if (code == GLX_TRANSPARENT_BLUE_VALUE)
+        return &fb->transparent_blue_value;
+    if (code == GLX_TRANSPARENT_ALPHA_VALUE)
+        return &fb->transparent_alpha_value;
+    if (code == GLX_BIND_TO_TEXTURE_RGBA_EXT)
+        return &fb->bind_to_texture_rgba_ext;
+    return NULL;
+}
+
+#ifdef DEBUG
+static const char*
+code_to_string(uint32_t code)
+{
+    if (code == GLX_FBCONFIG_ID)  return "GLX_FBCONFIG_ID";
+    if (code == GLX_BUFFER_SIZE)  return "GLX_BUFFER_SIZE";
+    if (code == GLX_LEVEL)        return "GLX_LEVEL";
+    if (code == GLX_DOUBLEBUFFER) return "GLX_DOUBLEBUFFER";
+    if (code == GLX_STEREO)       return "GLX_STEREO";
+    if (code == GLX_AUX_BUFFERS)  return "GLX_AUX_BUFFERS";
+    if (code == GLX_RED_SIZE)     return "GLX_RED_SIZE";
+    if (code == GLX_GREEN_SIZE)   return "GLX_GREEN_SIZE";
+    if (code == GLX_BLUE_SIZE)    return "GLX_BLUE_SIZE";
+    if (code == GLX_ALPHA_SIZE)   return "GLX_ALPHA_SIZE";
+    if (code == GLX_DEPTH_SIZE)   return "GLX_DEPTH_SIZE";
+    if (code == GLX_STENCIL_SIZE)     return "GLX_STENCIL_SIZE";
+    if (code == GLX_ACCUM_RED_SIZE)   return "GLX_ACCUM_RED_SIZE";
+    if (code == GLX_ACCUM_GREEN_SIZE) return "GLX_ACCUM_GREEN_SIZE";
+    if (code == GLX_ACCUM_BLUE_SIZE)  return "GLX_ACCUM_BLUE_SIZE";
+    if (code == GLX_ACCUM_ALPHA_SIZE) return "GLX_ACCUM_ALPHA_SIZE";
+    if (code == GLX_RENDER_TYPE)      return "GLX_RENDER_TYPE";
+    if (code == GLX_DRAWABLE_TYPE)    return "GLX_DRAWABLE_TYPE";
+    if (code == GLX_X_RENDERABLE)     return "GLX_X_RENDERABLE";
+    if (code == GLX_X_VISUAL_TYPE)    return "GLX_X_VISUAL_TYPE";
+    if (code == GLX_CONFIG_CAVEAT)    return "GLX_CONFIG_CAVEAT";
+    if (code == GLX_TRANSPARENT_TYPE)
+        return "GLX_TRANSPARENT_TYPE";
+    if (code == GLX_TRANSPARENT_INDEX_VALUE)
+        return "GLX_TRANSPARENT_INDEX_VALUE";
+    if (code == GLX_TRANSPARENT_RED_VALUE)
+        return "GLX_TRANSPARENT_RED_VALUE";
+    if (code == GLX_TRANSPARENT_GREEN_VALUE)
+        return "GLX_TRANSPARENT_GREEN_VALUE";
+    if (code == GLX_TRANSPARENT_BLUE_VALUE)
+        return "GLX_TRANSPARENT_BLUE_VALUE";
+    if (code == GLX_TRANSPARENT_ALPHA_VALUE)
+        return "GLX_TRANSPARENT_ALPHA_VALUE";
+    if (code == GLX_BIND_TO_TEXTURE_RGBA_EXT)
+        return "GLX_BIND_TO_TEXTURE_RGBA_EXT";
+    return NULL;
+}
+#endif
+
+static void
+default_config(d_glx_fb_config_t *fb)
+{
+    fb->fbconfig_id = GLX_DONT_CARE;
+    fb->buffer_size = 0;
+    fb->level = 0;
+    fb->doublebuffer = GLX_DONT_CARE;
+    fb->stereo = FALSE;
+    fb->aux_buffers = 0;
+    fb->red_size = 0;
+    fb->green_size = 0;
+    fb->blue_size = 0;
+    fb->alpha_size = 0;
+    fb->depth_size = 0;
+    fb->stencil_size = 0;
+    fb->accum_red_size = 0;
+    fb->accum_green_size = 0;
+    fb->accum_blue_size = 0;
+    fb->accum_alpha_size = 0;
+    fb->render_type = GLX_RGBA_BIT;
+    fb->drawable_type = GLX_WINDOW_BIT;
+    fb->x_renderable = GLX_DONT_CARE;
+    fb->x_visual_type = GLX_DONT_CARE;
+    fb->config_caveat = GLX_DONT_CARE;
+    fb->transparent_type = GLX_NONE;
+    fb->transparent_index_value = GLX_DONT_CARE;
+    fb->transparent_red_value = GLX_DONT_CARE;
+    fb->transparent_green_value = GLX_DONT_CARE;
+    fb->transparent_blue_value = GLX_DONT_CARE;
+    fb->transparent_alpha_value = GLX_DONT_CARE;
+    fb->bind_to_texture_rgba_ext = GLX_DONT_CARE;
+}
+
+static gboolean
+match_config(const d_glx_fb_config_t *match, const d_glx_fb_config_t *fb)
+{
+    if (match->fbconfig_id != GLX_DONT_CARE &&
+        fb->fbconfig_id != match->fbconfig_id)
+        return FALSE;
+    if (fb->buffer_size < match->buffer_size)
+        return FALSE;
+    if (fb->level != match->level)
+        return FALSE;
+    if (match->doublebuffer != GLX_DONT_CARE &&
+        fb->doublebuffer != match->doublebuffer)
+        return FALSE;
+    if (fb->stereo != match->stereo)
+        return FALSE;
+    if (fb->aux_buffers < match->aux_buffers)
+        return FALSE;
+    if (match->red_size != 0 && match->red_size == GLX_DONT_CARE &&
+        fb->red_size < match->red_size)
+        return FALSE;
+    if (match->green_size != 0 && match->green_size == GLX_DONT_CARE &&
+        fb->green_size < match->green_size)
+        return FALSE;
+    if (match->blue_size != 0 && match->blue_size == GLX_DONT_CARE &&
+        fb->blue_size < match->blue_size)
+        return FALSE;
+    if (match->alpha_size != 0 && match->alpha_size == GLX_DONT_CARE &&
+        fb->alpha_size < match->alpha_size)
+        return FALSE;
+    if (fb->depth_size < match->depth_size)
+        return FALSE;
+    if (fb->stencil_size < match->stencil_size)
+        return FALSE;
+    if (fb->accum_red_size < match->accum_red_size)
+        return FALSE;
+    if (fb->accum_green_size < match->accum_green_size)
+        return FALSE;
+    if (fb->accum_blue_size < match->accum_blue_size)
+        return FALSE;
+    if (fb->accum_alpha_size < match->accum_alpha_size)
+        return FALSE;
+    if ((fb->render_type & match->render_type) != match->render_type)
+        return FALSE;
+    if ((fb->drawable_type & match->drawable_type) != match->drawable_type)
+        return FALSE;
+    if (match->x_renderable != GLX_DONT_CARE &&
+        fb->x_renderable != match->x_renderable)
+        return FALSE;
+    if (match->x_visual_type != GLX_DONT_CARE &&
+        (match->drawable_type & GLX_WINDOW_BIT) &&
+        match->x_renderable != FALSE &&
+        fb->x_visual_type != match->x_visual_type)
+        return FALSE;
+    if (match->config_caveat != GLX_DONT_CARE &&
+        fb->config_caveat != match->config_caveat)
+        return FALSE;
+    if (fb->transparent_type != match->transparent_type)
+        return FALSE;
+    if (match->transparent_type == GLX_TRANSPARENT_INDEX &&
+        match->transparent_index_value != GLX_DONT_CARE &&
+        fb->transparent_index_value != match->transparent_index_value)
+        return FALSE;
+    if (match->transparent_type == GLX_TRANSPARENT_RGB &&
+        match->transparent_red_value != GLX_DONT_CARE &&
+        fb->transparent_red_value != match->transparent_red_value)
+        return FALSE;
+    if (match->transparent_type == GLX_TRANSPARENT_RGB &&
+        match->transparent_green_value != GLX_DONT_CARE &&
+        fb->transparent_green_value != match->transparent_green_value)
+        return FALSE;
+    if (match->transparent_type == GLX_TRANSPARENT_RGB &&
+        match->transparent_blue_value != GLX_DONT_CARE &&
+        fb->transparent_blue_value != match->transparent_blue_value)
+        return FALSE;
+    if (match->transparent_type == GLX_TRANSPARENT_RGB &&
+        match->transparent_alpha_value != GLX_DONT_CARE &&
+        fb->transparent_alpha_value != match->transparent_alpha_value)
+        return FALSE;
+    if (match->bind_to_texture_rgba_ext != GLX_DONT_CARE &&
+        fb->bind_to_texture_rgba_ext != match->bind_to_texture_rgba_ext)
+        return FALSE;
+    return TRUE;
+}
+
+static void
+build_config(uint32_t *props, uint32_t nprops, d_glx_fb_config_t *test)
+{
+    uint32_t i;
+
+    //assert(nprops == sizeof(d_glx_fb_config_t) / sizeof(uint32_t));
+
+    for (i = 0; i < nprops * 2; i += 2) {
+        uint32_t *val = code_to_ptr(test, props[i]);
+        if (val) *val = props[i+1];
+
+#ifdef DEBUG
+        {
+            const char *s = code_to_string(props[i]);
+            if (s)
+                printf("%s\t%x\n", s, props[i+1]);
+            else
+                printf("UNKNOWN %x\t%x\n", props[i], props[i+1]);
+        }
+#endif
+    }
+#ifdef DEBUG
+    printf("\n\n");
+#endif
+}
+
+static d_glx_fb_config_t sort_match;
+
+int compare_config(const void *va, const void *vb)
+{
+    const d_glx_fb_config_t *a = va, *b = vb;
+    uint32_t av, bv;
+
+    if (a->config_caveat != b->config_caveat) {
+        if (a->config_caveat == GLX_NONE) return -1;
+        if (b->config_caveat == GLX_NONE) return 1;
+        if (a->config_caveat == GLX_SLOW_CONFIG) return -1;
+        if (b->config_caveat == GLX_SLOW_CONFIG) return 1;
+    }
+
+    av = bv = 0;
+    if (sort_match.red_size != 0 && sort_match.red_size != GLX_DONT_CARE) {
+        av += a->red_size;
+        bv += b->red_size;
+    }
+    if (sort_match.green_size != 0 && sort_match.green_size != GLX_DONT_CARE) {
+        av += a->green_size;
+        bv += b->green_size;
+    }
+    if (sort_match.blue_size != 0 && sort_match.blue_size != GLX_DONT_CARE) {
+        av += a->blue_size;
+        bv += b->blue_size;
+    }
+    if (sort_match.alpha_size != 0 && sort_match.alpha_size != GLX_DONT_CARE) {
+        av += a->alpha_size;
+        bv += b->alpha_size;
+    }
+    if (av != bv)
+        return av > bv ? -1 : 1;
+
+    if (a->buffer_size < b->buffer_size)
+        return -1;
+    if (b->buffer_size < a->buffer_size)
+        return 1;
+
+    if (a->doublebuffer == FALSE && b->doublebuffer == TRUE)
+        return -1;
+    if (b->doublebuffer == FALSE && a->doublebuffer == TRUE)
+        return 1;
+
+    if (a->aux_buffers < b->aux_buffers)
+        return -1;
+    if (b->aux_buffers < a->aux_buffers)
+        return 1;
+
+    if (a->depth_size > b->depth_size)
+        return -1;
+    if (b->depth_size > a->depth_size)
+        return 1;
+
+    if (a->stencil_size < b->stencil_size)
+        return -1;
+    if (b->stencil_size < a->stencil_size)
+        return 1;
+
+    av = bv = 0;
+    if (sort_match.accum_red_size != 0 &&
+        sort_match.accum_red_size != GLX_DONT_CARE)
+    {
+        av += a->accum_red_size;
+        bv += b->accum_red_size;
+    }
+    if (sort_match.accum_green_size != 0 &&
+        sort_match.accum_green_size != GLX_DONT_CARE)
+    {
+        av += a->accum_green_size;
+        bv += b->accum_green_size;
+    }
+    if (sort_match.accum_blue_size != 0 &&
+        sort_match.accum_blue_size != GLX_DONT_CARE)
+    {
+        av += a->accum_blue_size;
+        bv += b->accum_blue_size;
+    }
+    if (sort_match.accum_alpha_size != 0 &&
+        sort_match.accum_alpha_size != GLX_DONT_CARE)
+    {
+        av += a->accum_alpha_size;
+        bv += b->accum_alpha_size;
+    }
+    if (av != bv)
+        return av > bv ? -1 : 1;
+
+    if (a->x_visual_type != b->x_visual_type) {
+        if (a->x_visual_type == GLX_TRUE_COLOR) return -1;
+        if (b->x_visual_type == GLX_TRUE_COLOR) return 1;
+        if (a->x_visual_type == GLX_DIRECT_COLOR) return -1;
+        if (b->x_visual_type == GLX_DIRECT_COLOR) return 1;
+        if (a->x_visual_type == GLX_PSEUDO_COLOR) return -1;
+        if (b->x_visual_type == GLX_PSEUDO_COLOR) return 1;
+        if (a->x_visual_type == GLX_STATIC_COLOR) return -1;
+        if (b->x_visual_type == GLX_STATIC_COLOR) return 1;
+        if (a->x_visual_type == GLX_GRAY_SCALE) return -1;
+        if (b->x_visual_type == GLX_GRAY_SCALE) return 1;
+    }
+
+    return 0;
+}
+
+d_glx_fb_config_t*
+glxcompat_choose_fb_config(xcb_connection_t *conn, int screen,
+                           const uint32_t *attrs, int *nret)
+{
+    xcb_glx_get_fb_configs_cookie_t ck;
+    xcb_glx_get_fb_configs_reply_t *rep;
+    uint32_t *props;
+    const uint32_t *attr_it;
+    unsigned int nprops, ncon, i;
+    d_glx_fb_config_t *ret, match, test;
+
+    *nret = 0;
+    ret = NULL;
+
+    ck = xcb_glx_get_fb_configs(conn, screen);
+    rep = xcb_glx_get_fb_configs_reply(conn, ck, NULL);
+    if (!rep) return ret;
+
+    props = xcb_glx_get_fb_configs_property_list(rep);
+    ncon = rep->num_FB_configs;
+    nprops = rep->num_properties;
+    assert(xcb_glx_get_fb_configs_property_list_length(rep) ==
+           (int)(ncon * nprops * 2));
+
+    default_config(&match);
+
+    for (attr_it = attrs; *attr_it != XCB_NONE; attr_it+=2) {
+        uint32_t *val = code_to_ptr(&match, attr_it[0]);
+        if (val) *val = attr_it[1];
+    }
+
+    for (i = 0; i < ncon; ++i) {
+        default_config(&test);
+        build_config(&props[i*(nprops*2)], nprops, &test);
+        if (match_config(&match, &test)) {
+            ++*nret;
+            ret = realloc(ret, sizeof(d_glx_fb_config_t) * *nret);
+            ret[*nret-1] = test;
+        }
+    }
+
+    if (*nret) {
+        sort_match = match;
+        qsort(ret, *nret, sizeof(d_glx_fb_config_t), compare_config);
+    }
+
+    return ret;
+}
+
+gboolean
+glxcompat_get_fb_config_attrib(d_glx_fb_config_t fb,
+                               uint32_t name,
+                               uint32_t *value)
+{
+    uint32_t *ptr = code_to_ptr(&fb, name);
+    assert(ptr != NULL);
+    if (ptr) *value = *ptr;
+    return !!ptr;
+}
diff --git a/glxcompat.h b/glxcompat.h
new file mode 100644 (file)
index 0000000..1e42997
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef dc_glxcompat_h
+#define dc_glxcompat_h
+
+#include <xcb/xcb.h>
+#include <glib.h>
+
+typedef struct d_glx_fb_config d_glx_fb_config_t;
+
+struct d_glx_fb_config {
+    uint32_t fbconfig_id;
+    uint32_t buffer_size;
+    uint32_t level;
+    uint32_t doublebuffer;
+    uint32_t stereo;
+    uint32_t aux_buffers;
+    uint32_t red_size;
+    uint32_t green_size;
+    uint32_t blue_size;
+    uint32_t alpha_size;
+    uint32_t depth_size;
+    uint32_t stencil_size;
+    uint32_t accum_red_size;
+    uint32_t accum_green_size;
+    uint32_t accum_blue_size;
+    uint32_t accum_alpha_size;
+    uint32_t render_type;
+    uint32_t drawable_type;
+    uint32_t x_renderable;
+    uint32_t x_visual_type;
+    uint32_t config_caveat;
+    uint32_t transparent_type;
+    uint32_t transparent_index_value;
+    uint32_t transparent_red_value;
+    uint32_t transparent_green_value;
+    uint32_t transparent_blue_value;
+    uint32_t transparent_alpha_value;
+    uint32_t bind_to_texture_rgba_ext;
+};
+
+d_glx_fb_config_t* glxcompat_choose_fb_config(xcb_connection_t *conn,
+                                              int screen,
+                                              const uint32_t *attrs,
+                                              int *nret);
+
+gboolean glxcompat_get_fb_config_attrib(d_glx_fb_config_t fb,
+                                        uint32_t name,
+                                        uint32_t *value);
+
+#endif
index 511bdb1f58502665ecdb5f663b83da4d4aef244a..8e89b009f13ff2e6800279836681ded9f7f42a20 100644 (file)
@@ -5,6 +5,7 @@
 #include "window.h"
 #include "display.h"
 #include "list.h"
+#include "glxcompat.h"
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -97,13 +98,13 @@ glxrender_init(d_screen_t *sc, int id)
     d->xshadowoff = 2;
     d->yshadowoff = 2;
 
-    if (!glxrender_check_visual(sc)) {
-        printf("unable to use the overlay window for GLX\n");
+    if (!(glxrender_find_fb_config(sc, d))) {
+        printf("unable to find FB configs\n");
         exit(1);
     }
 
-    if (!(glxrender_find_fb_config(sc, d))) {
-        printf("unable to find FB configs\n");
+    if (!glxrender_check_visual(sc)) {
+        printf("unable to use the overlay window for GLX\n");
         exit(1);
     }
 
@@ -254,6 +255,37 @@ glxrender_find_fb_config(d_screen_t *sc, data_t *d)
     uint32_t *vprops, *fbprops;
     uint32_t db, stencil, depthsize;
 
+    {
+        static const uint32_t 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
+        };
+
+        d_glx_fb_config_t *fbcons;
+        int i, numfb;
+
+        fbcons = glxcompat_choose_fb_config(sc->dpy->conn, sc->num,
+                                            drawable_tfp_attrs, &numfb);
+        printf("found %d\n", numfb);
+        if (fbcons) {
+            for (i = 0; i < numfb; ++i) {
+                uint32_t v;
+                glxcompat_get_fb_config_attrib(fbcons[i], GLX_FBCONFIG_ID, &v);
+                printf("GLX_FBCONFIG_ID %x\n", v);
+            }
+            free(fbcons);
+        }
+        exit(0);
+    }
+
     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;
@@ -291,7 +323,6 @@ glxrender_find_fb_config(d_screen_t *sc, data_t *d)
         /* 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)
index 6d454c3979075d2b6eedba0a200612b9636cfeff..693c29c542bbb6657f16286c009e338ab2a05027 100644 (file)
--- a/screen.c
+++ b/screen.c
@@ -156,7 +156,7 @@ screen_init(d_screen_t *sc)
         xcb_composite_redirect_subwindows(sc->dpy->conn, sc->super->root,
                                           XCB_COMPOSITE_REDIRECT_AUTOMATIC);
 
-#if 1
+#if 0
     redir_ck =
         xcb_composite_redirect_subwindows(sc->dpy->conn, sc->super->root,
                                           XCB_COMPOSITE_REDIRECT_MANUAL);