15 #include <GL/glxtokens.h>
17 #include <GL/glxext.h>
28 typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *);
29 typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int);
32 void (*screen_paint)(d_screen_t *sc);
33 void (*screen_root_pixmap_change)(d_screen_t *sc);
34 void (*window_show)(d_window_t *w);
35 void (*window_zombie_dead)(d_window_t *w);
36 void (*window_resize)(d_window_t *w);
37 void (*window_reshape)(d_window_t *w);
43 GLXFBConfig fbconfig[MAX_DEPTH + 1];
47 GLXPixmap root_glpixmap;
49 BindEXTFunc bind_func;
50 ReleaseEXTFunc release_func;
61 xcb_xfixes_fetch_region_cookie_t ck_region;
65 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
67 static void glxrender_paint(d_screen_t *sc);
68 static void glxrender_root_pixmap_change(d_screen_t *sc);
69 static void paint_root(d_screen_t *sc, data_t *d);
70 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
71 int x, int y, GLfloat z);
72 static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
74 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
76 static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
77 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
78 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
80 static void glxrender_free_window_region(window_data_t *wd);
81 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
82 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
84 static void glxrender_window_show(d_window_t *window);
85 static void glxrender_window_zombie_dead(d_window_t *window);
86 static void glxrender_window_resize(d_window_t *window);
87 static void glxrender_window_reshape(d_window_t *window);
90 glxrender_init(d_screen_t *sc, int id)
92 static int context_visual_config[] = {
103 d = malloc(sizeof(data_t));
104 d->screen_paint = sc->screen_paint;
105 d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
106 d->window_show = sc->window_show;
107 d->window_zombie_dead = sc->window_zombie_dead;
108 d->window_resize = sc->window_resize;
109 d->window_reshape = sc->window_reshape;
110 screen_add_plugin_data(sc, plugin_id, d);
112 sc->screen_paint = glxrender_paint;
113 sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
114 sc->window_show = glxrender_window_show;
115 sc->window_zombie_dead = glxrender_window_zombie_dead;
116 sc->window_resize = glxrender_window_resize;
117 sc->window_reshape = glxrender_window_reshape;
119 d->shadowalpha = 0.2f; /* 20% */
123 vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
125 printf("unable to find a valid double buffered GL context to use\n");
129 d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
130 glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
133 if (!(glxrender_find_fb_config(sc, d))) {
134 printf("unable to find FB configs\n");
138 glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
139 glMatrixMode(GL_PROJECTION);
141 glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
143 glMatrixMode(GL_MODELVIEW);
145 glEnable(GL_TEXTURE_2D);
146 glEnable(GL_DEPTH_TEST);
148 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
149 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
152 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
154 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
156 d->bind_func = (BindEXTFunc)
157 glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
158 d->release_func = (ReleaseEXTFunc)
159 glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
161 glGenTextures(1, &d->root_texname);
162 d->root_glpixmap = XCB_NONE;
166 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
168 static const int drawable_tfp_attrs[] = {
169 GLX_CONFIG_CAVEAT, GLX_NONE,
170 GLX_DOUBLEBUFFER, FALSE,
176 GLX_RENDER_TYPE, GLX_RGBA_BIT,
177 GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
180 int db, stencil, depth, numfb, i;
182 XVisualInfo tvis, *visinfo;
184 fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
185 drawable_tfp_attrs, &numfb);
186 if (!fbcons) return FALSE;
188 for (i = 0; i <= MAX_DEPTH; i++) {
198 printf("looking for depth %d\n", i);
201 visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
203 /* pick the nicest visual for the depth */
204 for (j = 0; j < count; j++) {
205 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
209 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
215 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
221 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
227 /* use this visual */
228 vid = visinfo[j].visualid;
233 /* look for an fbconfig for this visual */
234 for (j = 0; j < numfb; ++j) {
235 glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
236 GLX_VISUAL_ID, &value);
237 if ((unsigned)value == vid) {
238 d->fbconfig[i] = fbcons[j];
240 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
241 (uint32_t)vid, (uint32_t)fbcons[j], i);
252 glxrender_free(d_screen_t *sc)
254 data_t *d = screen_find_plugin_data(sc, plugin_id);
256 glxrender_free_root_pixmap(sc, d);
259 screen_remove_plugin_data(sc, plugin_id);
263 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
271 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
277 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
279 glxrender_free_window_pixmap(w, d, wd);
280 glxrender_free_window_region(wd);
281 glDeleteTextures(1, &wd->texname);
286 glxrender_window_show(d_window_t *w)
291 d = screen_find_plugin_data(w->sc, plugin_id);
296 wd = window_find_plugin_data(w, plugin_id);
298 glxrender_window_free_data(w, d, wd);
300 wd = malloc(sizeof(window_data_t));
301 glGenTextures(1, &wd->texname);
302 wd->glpixmap = XCB_NONE;
303 wd->texcoords = NULL;
306 wd->waiting_region = FALSE;
308 window_add_plugin_data(w, plugin_id, wd);
310 glxrender_fetch_window_region(w, wd);
314 glxrender_window_zombie_dead(d_window_t *w)
319 d = screen_find_plugin_data(w->sc, plugin_id);
320 wd = window_find_plugin_data(w, plugin_id);
322 glxrender_window_free_data(w, d, wd);
323 window_remove_plugin_data(w, plugin_id);
327 d->window_zombie_dead(w);
331 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
333 /* this might cause an error, oh well */
335 glBindTexture(GL_TEXTURE_2D, wd->texname);
336 d->release_func(w->sc->dpy->xlib_dpy,
337 wd->glpixmap, GLX_FRONT_LEFT_EXT);
338 glBindTexture(GL_TEXTURE_2D, 0);
340 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
341 glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
342 wd->glpixmap = XCB_NONE;
348 glxrender_free_window_region(window_data_t *wd)
353 wd->texcoords = NULL;
360 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
362 /* this might cause an error, oh well */
363 if (d->root_glpixmap) {
364 glBindTexture(GL_TEXTURE_2D, d->root_texname);
365 d->release_func(sc->dpy->xlib_dpy,
366 d->root_glpixmap, GLX_FRONT_LEFT_EXT);
367 glBindTexture(GL_TEXTURE_2D, 0);
369 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
370 glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
371 d->root_glpixmap = XCB_NONE;
376 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
381 static int attrs[] = {
382 GLX_TEXTURE_FORMAT_EXT,
387 px = window_get_pixmap(w);
388 depth = window_get_depth(w);
392 if (!d->fbconfig[depth]) {
393 printf("no GL visual for depth %d\n", depth);
397 if (window_is_argb(w))
398 attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
400 attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
402 wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
407 glBindTexture(GL_TEXTURE_2D, wd->texname);
408 d->bind_func(w->sc->dpy->xlib_dpy,
409 wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
411 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
412 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
414 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
417 glBindTexture(GL_TEXTURE_2D, 0);
419 glxrender_update_window_region(w, wd);
423 glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
425 if (wd->waiting_region) return;
428 xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
429 window_get_region(w));
430 wd->waiting_region = TRUE;
431 xcb_flush(w->sc->dpy->conn);
435 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
437 xcb_xfixes_fetch_region_reply_t *rep;
438 xcb_rectangle_t area, *rects;
439 int nrects, i, j, x, y, wid, hei, bwid;
441 if (!wd->waiting_region) return;
443 window_get_area(w, &x, &y, &wid, &hei, &bwid);
446 area.width = wid + bwid * 2;
447 area.height = hei + bwid * 2;
449 rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
455 rects = xcb_xfixes_fetch_region_rectangles(rep);
456 nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
459 wd->texcoords = (GLfloat*)realloc(wd->texcoords,
460 sizeof(GLfloat) * (nrects * 4));
461 wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
464 for (i = j = 0; i < nrects * 4; ++j, i += 4) {
465 wd->texcoords[i+LEFT] =
466 (GLfloat)(rects[j].x - x) / (GLfloat)area.width;
467 wd->texcoords[i+TOP] =
468 (GLfloat)(rects[j].y - y) / (GLfloat)area.height;
469 wd->texcoords[i+RIGHT] =
470 (GLfloat)(rects[j].x - x + rects[j].width) /
472 wd->texcoords[i+BOTTOM] =
473 (GLfloat)(rects[j].y - y + rects[j].height) /
474 (GLfloat)area.height;
476 wd->vertices[i+LEFT] = rects[j].x - x;
477 wd->vertices[i+TOP] = rects[j].y - y;
478 wd->vertices[i+RIGHT] = rects[j].x - x + rects[j].width;
479 wd->vertices[i+BOTTOM] = rects[j].y - y + rects[j].height;
485 wd->waiting_region = FALSE;
489 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
492 static int attrs[] = {
493 GLX_TEXTURE_FORMAT_EXT,
494 GLX_TEXTURE_FORMAT_RGB_EXT,
498 px = screen_get_root_pixmap(sc);
501 if (!d->fbconfig[sc->super->root_depth]) {
502 printf("no GL visual for depth %d\n", sc->super->root_depth);
506 d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
507 d->fbconfig[sc->super->root_depth],
511 glBindTexture(GL_TEXTURE_2D, d->root_texname);
512 d->bind_func(sc->dpy->xlib_dpy,
513 d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
515 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
516 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
518 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
519 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
521 glBindTexture(GL_TEXTURE_2D, 0);
525 glxrender_window_resize(d_window_t *w)
530 d = screen_find_plugin_data(w->sc, plugin_id);
531 wd = window_find_plugin_data(w, plugin_id);
537 glxrender_free_window_pixmap(w, d, wd);
539 glxrender_free_window_region(wd);
540 glxrender_fetch_window_region(w, wd);
544 glxrender_window_reshape(d_window_t *w)
549 d = screen_find_plugin_data(w->sc, plugin_id);
550 wd = window_find_plugin_data(w, plugin_id);
553 d->window_reshape(w);
556 glxrender_free_window_pixmap(w, d, wd);
558 glxrender_free_window_region(wd);
559 glxrender_fetch_window_region(w, wd);
563 glxrender_root_pixmap_change(d_screen_t *sc)
567 d = screen_find_plugin_data(sc, plugin_id);
568 glxrender_free_root_pixmap(sc, d);
571 d->screen_root_pixmap_change(sc);
575 glxrender_paint(d_screen_t *sc)
577 data_t *d = screen_find_plugin_data(sc, plugin_id);
581 //printf("painting\n");
583 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
585 /* add 0.1f to keep everything above the root */
586 z = list_length(sc->stacking) * 0.1f + 0.1f;
587 for (it = list_top(sc->stacking); it; it = it->next) {
588 d_window_t *w = it->data;
590 if (!window_is_input_only(w) &&
591 (window_is_mapped(w) || window_is_zombie(w)))
593 int x, y, width, height, bwidth;
597 window_get_area(w, &x, &y, &width, &height, &bwidth);
599 if (!(x < sc->super->width_in_pixels &&
600 y < sc->super->height_in_pixels &&
601 (x + width > 0 || x + width + d->xshadowoff > 0) &&
602 (y + height > 0 || y + height + d->yshadowoff > 0)))
607 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
610 wd = window_find_plugin_data(w, plugin_id);
614 paint_window(w, d, wd, x, y, z - 0.05f);
626 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
628 for (it = list_bottom(sc->stacking); it; it = it->prev) {
629 d_window_t *w = it->data;
631 if (!window_is_input_only(w) &&
632 (window_is_mapped(w) || window_is_zombie(w)))
634 int x, y, width, height, bwidth;
640 window_get_area(w, &x, &y, &width, &height, &bwidth);
642 if (!(x < sc->super->width_in_pixels &&
643 y < sc->super->height_in_pixels &&
644 (x + width > 0 || x + width + d->xshadowoff > 0) &&
645 (y + height > 0 || y + height + d->yshadowoff > 0)))
650 opac = window_get_opacity(w);
651 opaque = !window_is_argb(w) && opac == 0xffff;
653 wd = window_find_plugin_data(w, plugin_id);
658 alpha = d->shadowalpha;
662 glColor4f(0.0f, 0.0f, 0.0f, alpha);
663 paint_shadow(d, wd, x, y, z);
667 glColor4us(opac, opac, opac, opac);
668 paint_window(w, d, wd, x, y, z + 0.05f);
677 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
678 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
681 //xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
682 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
684 /* call the function we replaced in the chain */
689 paint_root(d_screen_t *sc, data_t *d)
691 if (!d->root_glpixmap)
692 glxrender_update_root_pixmap(sc, d);
694 glBindTexture(GL_TEXTURE_2D, d->root_texname);
699 glVertex3i(sc->super->width_in_pixels, 0, 0);
701 glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
703 glVertex3i(0, sc->super->height_in_pixels, 0);
706 glBindTexture(GL_TEXTURE_2D, 0);
710 paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
716 glxrender_update_window_pixmap(w, d, wd);
718 if (wd->nrects < 1) return;
720 glBindTexture(GL_TEXTURE_2D, wd->texname);
723 for (i = 0; i < wd->nrects * 4; i += 4) {
724 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
725 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
726 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
727 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
728 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
729 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
730 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
731 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
735 glBindTexture(GL_TEXTURE_2D, 0);
739 paint_shadow(data_t *d, window_data_t *wd, int x, int y, GLfloat z)
743 if (wd->nrects < 1) return;
745 /* shape the shadow to the window */
746 glBindTexture(GL_TEXTURE_2D, wd->texname);
752 for (i = 0; i < wd->nrects * 4; i += 4) {
753 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
754 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
755 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
756 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
757 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
758 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
759 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
760 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
764 glBindTexture(GL_TEXTURE_2D, 0);