--- /dev/null
+#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;
+}