i dunno, even the clear isn't working for gl right now
[dana/dcompmgr.git] / glxrender.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "display.h"
7 #include "list.h"
8 #include "glxcompat.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <stdlib.h>
13
14 #include <xcb/glx.h>
15 //#include <GL/glext.h>
16 //#include <GL/glxext.h>
17 #include <GL/glxtokens.h>
18 #include <GL/gl.h>
19
20 #define MAX_DEPTH 32
21
22 static int plugin_id;
23
24 typedef struct {
25     void (*screen_paint)(d_screen_t *sc);
26     void (*screen_root_pixmap_change)(d_screen_t *sc);
27     void (*window_show)(d_window_t *w);
28     void (*window_zombie_dead)(d_window_t *w);
29     void (*window_resize)(d_window_t *w);
30     void (*window_reshape)(d_window_t *w);
31
32     uint16_t shadowalpha;
33     int xshadowoff;
34     int yshadowoff;
35
36     uint32_t fbconfig[MAX_DEPTH + 1];
37
38     xcb_glx_context_t context;
39     xcb_glx_context_tag_t context_tag;
40 } data_t;
41
42 typedef struct {
43     GLuint texname;
44     xcb_glx_pixmap_t glpixmap;
45 } window_data_t;
46
47 static uint32_t glxrender_visual_info(uint32_t *props, int vis, int numprops,
48                                       uint32_t name);
49 static gboolean glxrender_check_visual(d_screen_t *sc);
50 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
51
52 static void glxrender_paint(d_screen_t *sc);
53 static void glxrender_root_pixmap_change(d_screen_t *sc);
54 static void paint_root(d_screen_t *sc, data_t *d);
55 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
56                          gboolean opaque, int x, int y, int width,
57                          int height, int bwidth);
58 static void paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
59                          int x, int y, int width, int height, int bwidth);
60 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
61                                            window_data_t *wd);
62 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
63                                          window_data_t *wd);
64 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
65
66 static void glxrender_window_show(d_window_t *window);
67 static void glxrender_window_zombie_dead(d_window_t *window);
68 static void glxrender_window_resize(d_window_t *window);
69 static void glxrender_window_reshape(d_window_t *window);
70
71 void
72 glxrender_init(d_screen_t *sc, int id)
73 {
74     xcb_void_cookie_t ck;
75     xcb_generic_error_t *err;
76     xcb_glx_make_current_cookie_t curck;
77     xcb_glx_make_current_reply_t *currep;
78     xcb_visualid_t vis;
79
80     plugin_id = id;
81
82     data_t *d = malloc(sizeof(data_t));
83     d->screen_paint = sc->screen_paint;
84     d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
85     d->window_show = sc->window_show;
86     d->window_zombie_dead = sc->window_zombie_dead;
87     d->window_resize = sc->window_resize;
88     d->window_reshape = sc->window_reshape;
89     screen_add_plugin_data(sc, plugin_id, d);
90
91     sc->screen_paint = glxrender_paint;
92     sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
93     sc->window_show = glxrender_window_show;
94     sc->window_zombie_dead = glxrender_window_zombie_dead;
95     sc->window_resize = glxrender_window_resize;
96     sc->window_reshape = glxrender_window_reshape;
97
98     d->shadowalpha = 0x3333; /* 20% */
99     d->xshadowoff = 2;
100     d->yshadowoff = 2;
101
102     if (!(glxrender_find_fb_config(sc, d))) {
103         printf("unable to find FB configs\n");
104         exit(1);
105     }
106
107     if (!glxrender_check_visual(sc)) {
108         printf("unable to use the overlay window for GLX\n");
109         exit(1);
110     }
111
112     d->context = xcb_generate_id(sc->dpy->conn);
113     ck = xcb_glx_create_context_checked(sc->dpy->conn, d->context,
114                                         sc->overlay_visual,
115                                         sc->num, XCB_NONE, GL_TRUE);
116     if ((err = xcb_request_check(sc->dpy->conn, ck))) {
117         printf("context creation failed\n");
118         display_error(sc->dpy, err);
119         free(err);
120         exit(1);
121     }
122
123     curck = xcb_glx_make_current(sc->dpy->conn,
124                                  sc->overlay, d->context, XCB_NONE);
125     currep = xcb_glx_make_current_reply(sc->dpy->conn, curck, &err);
126     if (!currep) {
127         if (err) {
128             display_error(sc->dpy, err);
129             free(err);
130         }
131         printf("make current failed\n");
132         exit(1);
133     }
134     d->context_tag = currep->context_tag;
135     free(currep);
136
137     glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
138     glMatrixMode(GL_PROJECTION);
139     glLoadIdentity();
140     glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels,
141             0.0, -1.0, 100.0);
142     glMatrixMode(GL_MODELVIEW);
143     glLoadIdentity();
144     glClear(GL_COLOR_BUFFER_BIT);
145     glEnable(GL_TEXTURE_2D);
146     xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
147     glClearColor(0.4, 0.4, 0.4, 1.0);
148
149     //glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
150     glDisable(GL_BLEND);
151 /*
152   glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);                          
153   glEnable(GL_BLEND);
154 */
155 }
156
157 static uint32_t
158 glxrender_visual_info(uint32_t *props, int vis, int numprops, uint32_t name)
159 {
160     int s;
161
162     assert(numprops > 15);
163
164     /*
165     for (s = vis * numprops; s < vis*numprops + numprops; ++s)
166         printf("%x ", props[s]);
167     printf("\n");
168     */
169
170     s = vis * numprops;
171     switch (name) {
172     case GLX_VISUAL_ID:     return props[s+0];  /* id number */
173     case GLX_X_VISUAL_TYPE: return props[s+1];  /* XCB_CLASS_TRUE_COLOR etc */
174     case GLX_USE_GL:        return props[s+2];  /* boolean */
175     case GLX_RED_SIZE:      return props[s+3];  /* number */
176     case GLX_GREEN_SIZE:    return props[s+4];  /* number */
177     case GLX_BLUE_SIZE:     return props[s+5];  /* number */
178     case GLX_ALPHA_SIZE:    return props[s+6];  /* number */
179     case GLX_DOUBLEBUFFER:  return props[s+11]; /* boolean */
180     case GLX_DEPTH_SIZE:    return props[s+14]; /* number */
181     case GLX_STENCIL_SIZE:  return props[s+15]; /* number */
182     default: assert(0);
183     }
184 }
185
186 static gboolean
187 glxrender_check_visual(d_screen_t *sc)
188 {
189     xcb_glx_get_visual_configs_cookie_t ck;
190     xcb_glx_get_visual_configs_reply_t *rep;
191     gboolean ok = FALSE;
192
193     ck = xcb_glx_get_visual_configs_unchecked(sc->dpy->conn, sc->num);
194     rep = xcb_glx_get_visual_configs_reply(sc->dpy->conn, ck, NULL);
195     if (rep) {
196         uint32_t *props;
197         unsigned int i, nprops;
198
199         props = xcb_glx_get_visual_configs_property_list(rep);
200         nprops = rep->num_properties;
201
202         for (i = 0; i < rep->num_visuals; ++i) {
203             /* look for the overlay's visual */
204             if (glxrender_visual_info(props, i, nprops, GLX_VISUAL_ID) !=
205                 sc->overlay_visual)
206             {
207                 continue;
208             }
209
210             if (!glxrender_visual_info(props, i, nprops, GLX_USE_GL)) {
211                 printf("overlay visual does not support GL\n");
212                 break;
213             }
214
215             if (!glxrender_visual_info(props, i, nprops, GLX_DOUBLEBUFFER)) {
216                 printf("overlay visual is not double buffered\n");
217                 break;
218             }
219
220             ok = TRUE; /* yippa ! */
221         }
222
223         free(rep);
224     }
225     return ok;
226 }
227
228 static gboolean
229 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
230 {
231     static const uint32_t drawable_tfp_attrs[] = {
232         GLX_CONFIG_CAVEAT, GLX_NONE,
233         GLX_DOUBLEBUFFER, FALSE,
234         GLX_DEPTH_SIZE, 0,
235         GLX_RED_SIZE, 1,
236         GLX_GREEN_SIZE, 1,
237         GLX_BLUE_SIZE, 1,
238         GLX_ALPHA_SIZE, 1,
239         GLX_RENDER_TYPE, GLX_RGBA_BIT,
240         GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
241         XCB_NONE
242     };
243     xcb_depth_iterator_t depth_it;
244     d_glx_fb_config_t *fbcons;
245     int numfb;
246
247     fbcons = glxcompat_choose_fb_config(sc->dpy->conn, sc->num,
248                                         drawable_tfp_attrs, &numfb);
249     if (!fbcons) return FALSE;
250
251     memset(d->fbconfig, 0, (MAX_DEPTH + 1) * sizeof(d->fbconfig[0]));
252
253     depth_it = xcb_screen_allowed_depths_iterator(sc->super);
254     for (; depth_it.rem; xcb_depth_next(&depth_it)) {
255         int j, k;
256         xcb_visualtype_t *visuals;
257         int nvisuals;
258
259         if (depth_it.data->depth > MAX_DEPTH) continue;
260
261         printf("looking for depth %d\n", depth_it.data->depth);
262
263         visuals = xcb_depth_visuals(depth_it.data);
264         nvisuals = xcb_depth_visuals_length(depth_it.data);
265
266         /* look for an fbconfig for this depth */
267         for (j = 0; j < numfb; ++j) {
268             uint32_t vid, fbid;
269             gboolean use;
270
271             //glxcompat_get_fb_config_attrib(fbcons[j], GLX_FBCONFIG_ID, &v);
272             //printf("trying fbconfig 0x%x\n", v);
273
274             glxcompat_get_fb_config_attrib(fbcons[j], GLX_VISUAL_ID, &vid);
275             glxcompat_get_fb_config_attrib(fbcons[j], GLX_FBCONFIG_ID, &fbid);
276
277             use = FALSE;
278             for (k = 0; k < nvisuals; ++k)
279                 //if (vid == visuals[k].visual_id) {
280                 if ((vid == 0x80 && depth_it.data->depth == 32) ||
281                     vid == 0x59) {
282                     use = TRUE;
283                     break;
284                 }
285
286             if (use) {
287                 d->fbconfig[depth_it.data->depth] = fbid;
288
289                 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
290                        vid, fbid, depth_it.data->depth);
291                 break;
292             }
293         }
294     }
295
296     free(fbcons);
297     return TRUE;
298 }
299
300 void
301 glxrender_free(d_screen_t *sc)
302 {
303     data_t *d = screen_find_plugin_data(sc, plugin_id);
304     free(d);
305     screen_remove_plugin_data(sc, plugin_id);
306 }
307
308 int
309 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
310 {
311     (void)sc;
312     (void)tv;
313     return FALSE;
314 }
315
316 void
317 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
318 {
319     (void)sc; (void)now;
320 }
321
322 void
323 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
324 {
325     glxrender_free_window_pixmap(w, d, wd);
326     glDeleteTextures(1, &wd->texname);
327     free(wd);
328 }
329
330 static void
331 glxrender_window_show(d_window_t *w)
332 {
333     data_t *d;
334     window_data_t *wd;
335
336     d = screen_find_plugin_data(w->sc, plugin_id);
337
338     /* pass it on */
339     d->window_show(w);
340
341     wd = window_find_plugin_data(w, plugin_id);
342     if (wd)
343         glxrender_window_free_data(w, d, wd);
344    
345     wd = malloc(sizeof(window_data_t));
346     glGenTextures(1, &wd->texname);
347     wd->glpixmap = XCB_NONE;
348
349     window_add_plugin_data(w, plugin_id, wd);
350 }
351
352 static void
353 glxrender_window_zombie_dead(d_window_t *w)
354 {
355     data_t *d;
356     window_data_t *wd;
357
358     d = screen_find_plugin_data(w->sc, plugin_id);
359     wd = window_find_plugin_data(w, plugin_id);
360     if (wd) {
361         glxrender_window_free_data(w, d, wd);
362         window_remove_plugin_data(w, plugin_id);
363     }
364
365     /* pass it on */
366     d->window_zombie_dead(w);
367 }
368
369 static void
370 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
371 {
372     /* this might cause an error, oh well */
373     if (wd->glpixmap) {
374         glBindTexture(GL_TEXTURE_2D, wd->texname);
375
376         {
377             /*
378               ReleaseTexImageEXT
379               1           CARD8           opcode (X assigned)
380               1           16              GLX opcode (glXVendorPrivate)
381               2           5               request length
382               4           1331            vendor specific opcode
383               4           CARD32          context tag
384               4           GLX_DRAWABLE    drawable
385               4           INT32           buffer
386             */
387             unsigned int len = (2 + 0) * sizeof(uint32_t);
388             uint32_t data[] = {
389                 wd->glpixmap,
390                 GLX_FRONT_LEFT_EXT
391             };
392             xcb_glx_vendor_private(w->sc->dpy->conn,
393                                    1331,
394                                    d->context_tag,
395                                    len, (uint8_t*)data);
396         }
397
398         glBindTexture(GL_TEXTURE_2D, 0);
399
400         xcb_glx_destroy_glx_pixmap(w->sc->dpy->conn, wd->glpixmap);
401         wd->glpixmap = XCB_NONE;
402     }
403 }
404
405 static void
406 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
407 {
408     xcb_pixmap_t px;
409     uint8_t depth;
410
411     static const uint32_t attrs[] = {
412         GLX_TEXTURE_FORMAT_EXT,
413         GLX_TEXTURE_FORMAT_RGBA_EXT
414     };
415
416     px = window_get_pixmap(w);
417     depth = window_get_depth(w);
418     //printf("%x %d %x\n", px, depth, d->fbconfig[depth]);
419     if (px && !d->fbconfig[depth])
420         printf("no GL visual for depth %d\n", depth);
421     else if (px) {
422         wd->glpixmap = xcb_generate_id(w->sc->dpy->conn);
423         printf("bind config 0x%x screen %d pixmap 0x%x glpixmap 0x%x "
424                "nattr %d\n",
425                d->fbconfig[depth], w->sc->num, px, wd->glpixmap,
426                sizeof(attrs)/sizeof(attrs[0]));
427         xcb_glx_create_pixmap(w->sc->dpy->conn, w->sc->num,
428                               d->fbconfig[depth],
429                               px, wd->glpixmap,
430                               sizeof(attrs)/sizeof(attrs[0]),
431                               attrs);
432
433         glBindTexture(GL_TEXTURE_2D, wd->texname);
434
435         {
436             /*
437               BindTexImageEXT
438               1           CARD8                   opcode (X assigned)
439               1           16                      GLX opcode (glXVendorPrivate)
440               2           6+n                     request length
441               4           1330                    vendor specific opcode
442               4           CARD32                  context tag
443               4           GLX_DRAWABLE            drawable
444               4           INT32                   buffer
445               4           CARD32                  num_attributes
446               4*n         LISTofATTRIBUTE_PAIR    attribute, value pairs.
447             */
448             unsigned int len = (3 + 0) * sizeof(uint32_t);
449             uint32_t data[] = {
450                 wd->glpixmap,
451                 GLX_FRONT_LEFT_EXT,
452                 0
453             };
454             xcb_glx_vendor_private(w->sc->dpy->conn,
455                                    1330,
456                                    d->context_tag,
457                                    len, (uint8_t*)data);
458         }
459
460         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
461         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
462
463         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
464         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
465         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
466
467         glBindTexture(GL_TEXTURE_2D, 0);
468     }
469 }
470
471 static void
472 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
473 {
474     xcb_pixmap_t px;
475
476     px = screen_get_root_pixmap(sc);
477     if (px) {
478     }
479 }
480
481 static void
482 glxrender_window_resize(d_window_t *w)
483 {
484     data_t *d;
485     window_data_t *wd;
486
487     d = screen_find_plugin_data(w->sc, plugin_id);
488     wd = window_find_plugin_data(w, plugin_id);
489
490     /* pass it on */
491     d->window_resize(w);
492
493     assert(wd != NULL);
494     glxrender_free_window_pixmap(w, d, wd);
495 }
496
497 static void
498 glxrender_window_reshape(d_window_t *w)
499 {
500     data_t *d;
501     window_data_t *wd;
502
503     d = screen_find_plugin_data(w->sc, plugin_id);
504     wd = window_find_plugin_data(w, plugin_id);
505
506     /* pass it on */
507     d->window_reshape(w);
508
509     assert(wd != NULL);
510     glxrender_free_window_pixmap(w, d, wd);
511 }
512
513 static void
514 glxrender_root_pixmap_change(d_screen_t *sc)
515 {
516     data_t *d;
517
518     d = screen_find_plugin_data(sc, plugin_id);
519     int a; /* XXX free things here */
520     //if (d->root_picture) {
521     //    xcb_render_free_picture(sc->dpy->conn, d->root_picture);
522     //    d->root_picture = XCB_NONE;
523     //}
524
525     /* pass it on */
526     d->screen_root_pixmap_change(sc);
527 }
528
529 static void
530 glxrender_paint(d_screen_t *sc)
531 {
532     data_t *d = screen_find_plugin_data(sc, plugin_id);
533     d_list_it_t *it;
534
535     //printf("painting\n");
536
537     paint_root(sc, d);
538
539     for (it = list_bottom(sc->stacking); it; it = it->prev) {
540         d_window_t *w = it->data;
541
542         if (!window_is_input_only(w) &&
543             (window_is_mapped(w) || window_is_zombie(w)))
544         {
545             int x, y, width, height, bwidth;
546             gboolean opaque;
547             window_data_t *wd;
548
549             window_get_area(w, &x, &y, &width, &height, &bwidth);
550
551             if (!(x < sc->super->width_in_pixels &&
552                   y < sc->super->height_in_pixels &&
553                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
554                   (y + height > 0 || y + height + d->yshadowoff > 0)))
555             {
556                 continue;
557             }
558
559             opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
560
561             wd = window_find_plugin_data(w, plugin_id);
562
563             //paint_shadow(w, d, wd, x, y, width, height, bwidth);
564             //paint_window(w, d, wd, opaque, x, y, width, height, bwidth);
565         }
566     }
567
568     xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
569
570     /* call the function we replaced in the chain */
571     d->screen_paint(sc);
572 }
573
574 static void
575 paint_root(d_screen_t *sc, data_t *d)
576 {
577     //if (!d->root_picture)
578     glxrender_update_root_pixmap(sc, d);
579
580     glClear(GL_COLOR_BUFFER_BIT);
581 }
582
583 static void
584 paint_window(d_window_t *w, data_t *d, window_data_t *wd, gboolean opaque,
585              int x, int y, int width, int height, int bwidth)
586 {
587     if (!wd->glpixmap)
588         glxrender_update_window_pixmap(w, d, wd);
589
590     glBindTexture(GL_TEXTURE_2D, wd->texname);
591     glBegin(GL_QUADS);
592     glColor3f(1.0, 1.0, 1.0);
593     glVertex2i(x, y);
594     glTexCoord2f(1, 0);
595     glVertex2i(x + width + bwidth, y);
596     glTexCoord2f(1, 1);
597     glVertex2i(x + width + bwidth,
598                y + height + bwidth);
599     glTexCoord2f(0, 1);
600     glVertex2i(x, y + height + bwidth);
601     glTexCoord2f(0, 0);
602     glEnd();
603 }
604
605 static void
606 paint_shadow(d_window_t *w, data_t *d, window_data_t *wd,
607              int x, int y, int width, int height, int bwidth)
608 {
609 /*
610     xcb_render_composite(w->sc->dpy->conn,
611                          XCB_RENDER_PICT_OP_OVER,
612                          wd->shadow_picture,
613                          wd->picture,
614                          d->overlay_buffer,
615                          0, 0, 0, 0,
616                          x+d->xshadowoff, y+d->yshadowoff,
617                          width + bwidth*2, height + bwidth *2);
618 */
619 }