i've reimplemented glXChooseFBConfig for xcb
[dana/dcompmgr.git] / glxcompat.c
1 #include "efence.h"
2
3 #include "glxcompat.h"
4 #include <xcb/glx.h>
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <GL/glxtokens.h>
9 #include <glib.h>
10
11 static uint32_t*
12 code_to_ptr(d_glx_fb_config_t *fb, uint32_t code)
13 {
14     if (code == GLX_FBCONFIG_ID)  return &fb->fbconfig_id;
15     if (code == GLX_BUFFER_SIZE)  return &fb->buffer_size;
16     if (code == GLX_LEVEL)        return &fb->level;
17     if (code == GLX_DOUBLEBUFFER) return &fb->doublebuffer;
18     if (code == GLX_STEREO)       return &fb->stereo;
19     if (code == GLX_AUX_BUFFERS)  return &fb->aux_buffers;
20     if (code == GLX_RED_SIZE)     return &fb->red_size;
21     if (code == GLX_GREEN_SIZE)   return &fb->green_size;
22     if (code == GLX_BLUE_SIZE)    return &fb->blue_size;
23     if (code == GLX_ALPHA_SIZE)   return &fb->alpha_size;
24     if (code == GLX_DEPTH_SIZE)   return &fb->depth_size;
25     if (code == GLX_STENCIL_SIZE)     return &fb->stencil_size;
26     if (code == GLX_ACCUM_RED_SIZE)   return &fb->accum_red_size;
27     if (code == GLX_ACCUM_GREEN_SIZE) return &fb->accum_green_size;
28     if (code == GLX_ACCUM_BLUE_SIZE)  return &fb->accum_blue_size;
29     if (code == GLX_ACCUM_ALPHA_SIZE) return &fb->accum_alpha_size;
30     if (code == GLX_RENDER_TYPE)      return &fb->render_type;
31     if (code == GLX_DRAWABLE_TYPE)    return &fb->drawable_type;
32     if (code == GLX_X_RENDERABLE)     return &fb->x_renderable;
33     if (code == GLX_X_VISUAL_TYPE)    return &fb->x_visual_type;
34     if (code == GLX_CONFIG_CAVEAT)    return &fb->config_caveat;
35     if (code == GLX_TRANSPARENT_TYPE) return &fb->transparent_type;
36     if (code == GLX_TRANSPARENT_INDEX_VALUE)
37         return &fb->transparent_index_value;
38     if (code == GLX_TRANSPARENT_RED_VALUE)
39         return &fb->transparent_red_value;
40     if (code == GLX_TRANSPARENT_GREEN_VALUE)
41         return &fb->transparent_green_value;
42     if (code == GLX_TRANSPARENT_BLUE_VALUE)
43         return &fb->transparent_blue_value;
44     if (code == GLX_TRANSPARENT_ALPHA_VALUE)
45         return &fb->transparent_alpha_value;
46     if (code == GLX_BIND_TO_TEXTURE_RGBA_EXT)
47         return &fb->bind_to_texture_rgba_ext;
48     return NULL;
49 }
50
51 #ifdef DEBUG
52 static const char*
53 code_to_string(uint32_t code)
54 {
55     if (code == GLX_FBCONFIG_ID)  return "GLX_FBCONFIG_ID";
56     if (code == GLX_BUFFER_SIZE)  return "GLX_BUFFER_SIZE";
57     if (code == GLX_LEVEL)        return "GLX_LEVEL";
58     if (code == GLX_DOUBLEBUFFER) return "GLX_DOUBLEBUFFER";
59     if (code == GLX_STEREO)       return "GLX_STEREO";
60     if (code == GLX_AUX_BUFFERS)  return "GLX_AUX_BUFFERS";
61     if (code == GLX_RED_SIZE)     return "GLX_RED_SIZE";
62     if (code == GLX_GREEN_SIZE)   return "GLX_GREEN_SIZE";
63     if (code == GLX_BLUE_SIZE)    return "GLX_BLUE_SIZE";
64     if (code == GLX_ALPHA_SIZE)   return "GLX_ALPHA_SIZE";
65     if (code == GLX_DEPTH_SIZE)   return "GLX_DEPTH_SIZE";
66     if (code == GLX_STENCIL_SIZE)     return "GLX_STENCIL_SIZE";
67     if (code == GLX_ACCUM_RED_SIZE)   return "GLX_ACCUM_RED_SIZE";
68     if (code == GLX_ACCUM_GREEN_SIZE) return "GLX_ACCUM_GREEN_SIZE";
69     if (code == GLX_ACCUM_BLUE_SIZE)  return "GLX_ACCUM_BLUE_SIZE";
70     if (code == GLX_ACCUM_ALPHA_SIZE) return "GLX_ACCUM_ALPHA_SIZE";
71     if (code == GLX_RENDER_TYPE)      return "GLX_RENDER_TYPE";
72     if (code == GLX_DRAWABLE_TYPE)    return "GLX_DRAWABLE_TYPE";
73     if (code == GLX_X_RENDERABLE)     return "GLX_X_RENDERABLE";
74     if (code == GLX_X_VISUAL_TYPE)    return "GLX_X_VISUAL_TYPE";
75     if (code == GLX_CONFIG_CAVEAT)    return "GLX_CONFIG_CAVEAT";
76     if (code == GLX_TRANSPARENT_TYPE)
77         return "GLX_TRANSPARENT_TYPE";
78     if (code == GLX_TRANSPARENT_INDEX_VALUE)
79         return "GLX_TRANSPARENT_INDEX_VALUE";
80     if (code == GLX_TRANSPARENT_RED_VALUE)
81         return "GLX_TRANSPARENT_RED_VALUE";
82     if (code == GLX_TRANSPARENT_GREEN_VALUE)
83         return "GLX_TRANSPARENT_GREEN_VALUE";
84     if (code == GLX_TRANSPARENT_BLUE_VALUE)
85         return "GLX_TRANSPARENT_BLUE_VALUE";
86     if (code == GLX_TRANSPARENT_ALPHA_VALUE)
87         return "GLX_TRANSPARENT_ALPHA_VALUE";
88     if (code == GLX_BIND_TO_TEXTURE_RGBA_EXT)
89         return "GLX_BIND_TO_TEXTURE_RGBA_EXT";
90     return NULL;
91 }
92 #endif
93
94 static void
95 default_config(d_glx_fb_config_t *fb)
96 {
97     fb->fbconfig_id = GLX_DONT_CARE;
98     fb->buffer_size = 0;
99     fb->level = 0;
100     fb->doublebuffer = GLX_DONT_CARE;
101     fb->stereo = FALSE;
102     fb->aux_buffers = 0;
103     fb->red_size = 0;
104     fb->green_size = 0;
105     fb->blue_size = 0;
106     fb->alpha_size = 0;
107     fb->depth_size = 0;
108     fb->stencil_size = 0;
109     fb->accum_red_size = 0;
110     fb->accum_green_size = 0;
111     fb->accum_blue_size = 0;
112     fb->accum_alpha_size = 0;
113     fb->render_type = GLX_RGBA_BIT;
114     fb->drawable_type = GLX_WINDOW_BIT;
115     fb->x_renderable = GLX_DONT_CARE;
116     fb->x_visual_type = GLX_DONT_CARE;
117     fb->config_caveat = GLX_DONT_CARE;
118     fb->transparent_type = GLX_NONE;
119     fb->transparent_index_value = GLX_DONT_CARE;
120     fb->transparent_red_value = GLX_DONT_CARE;
121     fb->transparent_green_value = GLX_DONT_CARE;
122     fb->transparent_blue_value = GLX_DONT_CARE;
123     fb->transparent_alpha_value = GLX_DONT_CARE;
124     fb->bind_to_texture_rgba_ext = GLX_DONT_CARE;
125 }
126
127 static gboolean
128 match_config(const d_glx_fb_config_t *match, const d_glx_fb_config_t *fb)
129 {
130     if (match->fbconfig_id != GLX_DONT_CARE &&
131         fb->fbconfig_id != match->fbconfig_id)
132         return FALSE;
133     if (fb->buffer_size < match->buffer_size)
134         return FALSE;
135     if (fb->level != match->level)
136         return FALSE;
137     if (match->doublebuffer != GLX_DONT_CARE &&
138         fb->doublebuffer != match->doublebuffer)
139         return FALSE;
140     if (fb->stereo != match->stereo)
141         return FALSE;
142     if (fb->aux_buffers < match->aux_buffers)
143         return FALSE;
144     if (match->red_size != 0 && match->red_size == GLX_DONT_CARE &&
145         fb->red_size < match->red_size)
146         return FALSE;
147     if (match->green_size != 0 && match->green_size == GLX_DONT_CARE &&
148         fb->green_size < match->green_size)
149         return FALSE;
150     if (match->blue_size != 0 && match->blue_size == GLX_DONT_CARE &&
151         fb->blue_size < match->blue_size)
152         return FALSE;
153     if (match->alpha_size != 0 && match->alpha_size == GLX_DONT_CARE &&
154         fb->alpha_size < match->alpha_size)
155         return FALSE;
156     if (fb->depth_size < match->depth_size)
157         return FALSE;
158     if (fb->stencil_size < match->stencil_size)
159         return FALSE;
160     if (fb->accum_red_size < match->accum_red_size)
161         return FALSE;
162     if (fb->accum_green_size < match->accum_green_size)
163         return FALSE;
164     if (fb->accum_blue_size < match->accum_blue_size)
165         return FALSE;
166     if (fb->accum_alpha_size < match->accum_alpha_size)
167         return FALSE;
168     if ((fb->render_type & match->render_type) != match->render_type)
169         return FALSE;
170     if ((fb->drawable_type & match->drawable_type) != match->drawable_type)
171         return FALSE;
172     if (match->x_renderable != GLX_DONT_CARE &&
173         fb->x_renderable != match->x_renderable)
174         return FALSE;
175     if (match->x_visual_type != GLX_DONT_CARE &&
176         (match->drawable_type & GLX_WINDOW_BIT) &&
177         match->x_renderable != FALSE &&
178         fb->x_visual_type != match->x_visual_type)
179         return FALSE;
180     if (match->config_caveat != GLX_DONT_CARE &&
181         fb->config_caveat != match->config_caveat)
182         return FALSE;
183     if (fb->transparent_type != match->transparent_type)
184         return FALSE;
185     if (match->transparent_type == GLX_TRANSPARENT_INDEX &&
186         match->transparent_index_value != GLX_DONT_CARE &&
187         fb->transparent_index_value != match->transparent_index_value)
188         return FALSE;
189     if (match->transparent_type == GLX_TRANSPARENT_RGB &&
190         match->transparent_red_value != GLX_DONT_CARE &&
191         fb->transparent_red_value != match->transparent_red_value)
192         return FALSE;
193     if (match->transparent_type == GLX_TRANSPARENT_RGB &&
194         match->transparent_green_value != GLX_DONT_CARE &&
195         fb->transparent_green_value != match->transparent_green_value)
196         return FALSE;
197     if (match->transparent_type == GLX_TRANSPARENT_RGB &&
198         match->transparent_blue_value != GLX_DONT_CARE &&
199         fb->transparent_blue_value != match->transparent_blue_value)
200         return FALSE;
201     if (match->transparent_type == GLX_TRANSPARENT_RGB &&
202         match->transparent_alpha_value != GLX_DONT_CARE &&
203         fb->transparent_alpha_value != match->transparent_alpha_value)
204         return FALSE;
205     if (match->bind_to_texture_rgba_ext != GLX_DONT_CARE &&
206         fb->bind_to_texture_rgba_ext != match->bind_to_texture_rgba_ext)
207         return FALSE;
208     return TRUE;
209 }
210
211 static void
212 build_config(uint32_t *props, uint32_t nprops, d_glx_fb_config_t *test)
213 {
214     uint32_t i;
215
216     //assert(nprops == sizeof(d_glx_fb_config_t) / sizeof(uint32_t));
217
218     for (i = 0; i < nprops * 2; i += 2) {
219         uint32_t *val = code_to_ptr(test, props[i]);
220         if (val) *val = props[i+1];
221
222 #ifdef DEBUG
223         {
224             const char *s = code_to_string(props[i]);
225             if (s)
226                 printf("%s\t%x\n", s, props[i+1]);
227             else
228                 printf("UNKNOWN %x\t%x\n", props[i], props[i+1]);
229         }
230 #endif
231     }
232 #ifdef DEBUG
233     printf("\n\n");
234 #endif
235 }
236
237 static d_glx_fb_config_t sort_match;
238
239 int compare_config(const void *va, const void *vb)
240 {
241     const d_glx_fb_config_t *a = va, *b = vb;
242     uint32_t av, bv;
243
244     if (a->config_caveat != b->config_caveat) {
245         if (a->config_caveat == GLX_NONE) return -1;
246         if (b->config_caveat == GLX_NONE) return 1;
247         if (a->config_caveat == GLX_SLOW_CONFIG) return -1;
248         if (b->config_caveat == GLX_SLOW_CONFIG) return 1;
249     }
250
251     av = bv = 0;
252     if (sort_match.red_size != 0 && sort_match.red_size != GLX_DONT_CARE) {
253         av += a->red_size;
254         bv += b->red_size;
255     }
256     if (sort_match.green_size != 0 && sort_match.green_size != GLX_DONT_CARE) {
257         av += a->green_size;
258         bv += b->green_size;
259     }
260     if (sort_match.blue_size != 0 && sort_match.blue_size != GLX_DONT_CARE) {
261         av += a->blue_size;
262         bv += b->blue_size;
263     }
264     if (sort_match.alpha_size != 0 && sort_match.alpha_size != GLX_DONT_CARE) {
265         av += a->alpha_size;
266         bv += b->alpha_size;
267     }
268     if (av != bv)
269         return av > bv ? -1 : 1;
270
271     if (a->buffer_size < b->buffer_size)
272         return -1;
273     if (b->buffer_size < a->buffer_size)
274         return 1;
275
276     if (a->doublebuffer == FALSE && b->doublebuffer == TRUE)
277         return -1;
278     if (b->doublebuffer == FALSE && a->doublebuffer == TRUE)
279         return 1;
280
281     if (a->aux_buffers < b->aux_buffers)
282         return -1;
283     if (b->aux_buffers < a->aux_buffers)
284         return 1;
285
286     if (a->depth_size > b->depth_size)
287         return -1;
288     if (b->depth_size > a->depth_size)
289         return 1;
290
291     if (a->stencil_size < b->stencil_size)
292         return -1;
293     if (b->stencil_size < a->stencil_size)
294         return 1;
295
296     av = bv = 0;
297     if (sort_match.accum_red_size != 0 &&
298         sort_match.accum_red_size != GLX_DONT_CARE)
299     {
300         av += a->accum_red_size;
301         bv += b->accum_red_size;
302     }
303     if (sort_match.accum_green_size != 0 &&
304         sort_match.accum_green_size != GLX_DONT_CARE)
305     {
306         av += a->accum_green_size;
307         bv += b->accum_green_size;
308     }
309     if (sort_match.accum_blue_size != 0 &&
310         sort_match.accum_blue_size != GLX_DONT_CARE)
311     {
312         av += a->accum_blue_size;
313         bv += b->accum_blue_size;
314     }
315     if (sort_match.accum_alpha_size != 0 &&
316         sort_match.accum_alpha_size != GLX_DONT_CARE)
317     {
318         av += a->accum_alpha_size;
319         bv += b->accum_alpha_size;
320     }
321     if (av != bv)
322         return av > bv ? -1 : 1;
323
324     if (a->x_visual_type != b->x_visual_type) {
325         if (a->x_visual_type == GLX_TRUE_COLOR) return -1;
326         if (b->x_visual_type == GLX_TRUE_COLOR) return 1;
327         if (a->x_visual_type == GLX_DIRECT_COLOR) return -1;
328         if (b->x_visual_type == GLX_DIRECT_COLOR) return 1;
329         if (a->x_visual_type == GLX_PSEUDO_COLOR) return -1;
330         if (b->x_visual_type == GLX_PSEUDO_COLOR) return 1;
331         if (a->x_visual_type == GLX_STATIC_COLOR) return -1;
332         if (b->x_visual_type == GLX_STATIC_COLOR) return 1;
333         if (a->x_visual_type == GLX_GRAY_SCALE) return -1;
334         if (b->x_visual_type == GLX_GRAY_SCALE) return 1;
335     }
336
337     return 0;
338 }
339
340 d_glx_fb_config_t*
341 glxcompat_choose_fb_config(xcb_connection_t *conn, int screen,
342                            const uint32_t *attrs, int *nret)
343 {
344     xcb_glx_get_fb_configs_cookie_t ck;
345     xcb_glx_get_fb_configs_reply_t *rep;
346     uint32_t *props;
347     const uint32_t *attr_it;
348     unsigned int nprops, ncon, i;
349     d_glx_fb_config_t *ret, match, test;
350
351     *nret = 0;
352     ret = NULL;
353
354     ck = xcb_glx_get_fb_configs(conn, screen);
355     rep = xcb_glx_get_fb_configs_reply(conn, ck, NULL);
356     if (!rep) return ret;
357
358     props = xcb_glx_get_fb_configs_property_list(rep);
359     ncon = rep->num_FB_configs;
360     nprops = rep->num_properties;
361     assert(xcb_glx_get_fb_configs_property_list_length(rep) ==
362            (int)(ncon * nprops * 2));
363
364     default_config(&match);
365
366     for (attr_it = attrs; *attr_it != XCB_NONE; attr_it+=2) {
367         uint32_t *val = code_to_ptr(&match, attr_it[0]);
368         if (val) *val = attr_it[1];
369     }
370
371     for (i = 0; i < ncon; ++i) {
372         default_config(&test);
373         build_config(&props[i*(nprops*2)], nprops, &test);
374         if (match_config(&match, &test)) {
375             ++*nret;
376             ret = realloc(ret, sizeof(d_glx_fb_config_t) * *nret);
377             ret[*nret-1] = test;
378         }
379     }
380
381     if (*nret) {
382         sort_match = match;
383         qsort(ret, *nret, sizeof(d_glx_fb_config_t), compare_config);
384     }
385
386     return ret;
387 }
388
389 gboolean
390 glxcompat_get_fb_config_attrib(d_glx_fb_config_t fb,
391                                uint32_t name,
392                                uint32_t *value)
393 {
394     uint32_t *ptr = code_to_ptr(&fb, name);
395     assert(ptr != NULL);
396     if (ptr) *value = *ptr;
397     return !!ptr;
398 }