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_move)(d_window_t *w);
37 void (*window_resize)(d_window_t *w);
38 void (*window_reshape)(d_window_t *w);
44 GLXFBConfig fbconfig[MAX_DEPTH + 1];
48 GLXPixmap root_glpixmap;
50 BindEXTFunc bind_func;
51 ReleaseEXTFunc release_func;
63 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
65 static void glxrender_paint(d_screen_t *sc);
66 static void glxrender_root_pixmap_change(d_screen_t *sc);
67 static void paint_root(d_screen_t *sc, data_t *d);
68 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
70 static void paint_shadow(data_t *d, window_data_t *wd, GLfloat z);
71 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
73 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
74 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
76 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
77 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
79 static void glxrender_window_show(d_window_t *window);
80 static void glxrender_window_zombie_dead(d_window_t *window);
81 static void glxrender_window_move(d_window_t *window);
82 static void glxrender_window_resize(d_window_t *window);
83 static void glxrender_window_reshape(d_window_t *window);
86 glxrender_init(d_screen_t *sc, int id)
88 static int context_visual_config[] = {
99 d = malloc(sizeof(data_t));
100 d->screen_paint = sc->screen_paint;
101 d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
102 d->window_show = sc->window_show;
103 d->window_zombie_dead = sc->window_zombie_dead;
104 d->window_resize = sc->window_resize;
105 d->window_move = sc->window_move;
106 d->window_reshape = sc->window_reshape;
107 screen_add_plugin_data(sc, plugin_id, d);
109 sc->screen_paint = glxrender_paint;
110 sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
111 sc->window_show = glxrender_window_show;
112 sc->window_zombie_dead = glxrender_window_zombie_dead;
113 sc->window_resize = glxrender_window_resize;
114 sc->window_move = glxrender_window_move;
115 sc->window_reshape = glxrender_window_reshape;
117 d->shadowalpha = 0.2f; /* 20% */
121 vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
123 printf("unable to find a valid double buffered GL context to use\n");
127 d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
128 glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
131 if (!(glxrender_find_fb_config(sc, d))) {
132 printf("unable to find FB configs\n");
136 glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
137 glMatrixMode(GL_PROJECTION);
139 glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
141 glMatrixMode(GL_MODELVIEW);
143 glEnable(GL_TEXTURE_2D);
144 glEnable(GL_DEPTH_TEST);
146 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
147 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
150 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
151 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
154 d->bind_func = (BindEXTFunc)
155 glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
156 d->release_func = (ReleaseEXTFunc)
157 glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
159 glGenTextures(1, &d->root_texname);
160 d->root_glpixmap = XCB_NONE;
164 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
166 static const int drawable_tfp_attrs[] = {
167 GLX_CONFIG_CAVEAT, GLX_NONE,
168 GLX_DOUBLEBUFFER, FALSE,
174 GLX_RENDER_TYPE, GLX_RGBA_BIT,
175 GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
178 int db, stencil, depth, numfb, i;
180 XVisualInfo tvis, *visinfo;
182 fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
183 drawable_tfp_attrs, &numfb);
184 if (!fbcons) return FALSE;
186 for (i = 0; i <= MAX_DEPTH; i++) {
196 printf("looking for depth %d\n", i);
199 visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
201 /* pick the nicest visual for the depth */
202 for (j = 0; j < count; j++) {
203 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
207 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
213 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
219 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
225 /* use this visual */
226 vid = visinfo[j].visualid;
231 /* look for an fbconfig for this visual */
232 for (j = 0; j < numfb; ++j) {
233 glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
234 GLX_VISUAL_ID, &value);
235 if ((unsigned)value == vid) {
236 d->fbconfig[i] = fbcons[j];
238 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
239 (uint32_t)vid, (uint32_t)fbcons[j], i);
250 glxrender_free(d_screen_t *sc)
252 data_t *d = screen_find_plugin_data(sc, plugin_id);
254 glxrender_free_root_pixmap(sc, d);
257 screen_remove_plugin_data(sc, plugin_id);
261 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
269 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
275 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
277 glxrender_free_window_pixmap(w, d, wd);
278 glDeleteTextures(1, &wd->texname);
283 glxrender_window_show(d_window_t *w)
288 d = screen_find_plugin_data(w->sc, plugin_id);
293 wd = window_find_plugin_data(w, plugin_id);
295 glxrender_window_free_data(w, d, wd);
297 wd = malloc(sizeof(window_data_t));
298 glGenTextures(1, &wd->texname);
299 wd->glpixmap = XCB_NONE;
302 window_add_plugin_data(w, plugin_id, wd);
304 glxrender_update_window_pixmap(w, d, wd);
308 glxrender_window_zombie_dead(d_window_t *w)
313 d = screen_find_plugin_data(w->sc, plugin_id);
314 wd = window_find_plugin_data(w, plugin_id);
316 glxrender_window_free_data(w, d, wd);
317 window_remove_plugin_data(w, plugin_id);
321 d->window_zombie_dead(w);
325 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
327 /* this might cause an error, oh well */
329 glBindTexture(GL_TEXTURE_2D, wd->texname);
330 d->release_func(w->sc->dpy->xlib_dpy,
331 wd->glpixmap, GLX_FRONT_LEFT_EXT);
332 glBindTexture(GL_TEXTURE_2D, 0);
334 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
335 glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
336 wd->glpixmap = XCB_NONE;
347 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
349 /* this might cause an error, oh well */
350 if (d->root_glpixmap) {
351 glBindTexture(GL_TEXTURE_2D, d->root_texname);
352 d->release_func(sc->dpy->xlib_dpy,
353 d->root_glpixmap, GLX_FRONT_LEFT_EXT);
354 glBindTexture(GL_TEXTURE_2D, 0);
356 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
357 glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
358 d->root_glpixmap = XCB_NONE;
363 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
368 static int attrs[] = {
369 GLX_TEXTURE_FORMAT_EXT,
374 px = window_get_pixmap(w);
375 depth = window_get_depth(w);
379 if (!d->fbconfig[depth]) {
380 printf("no GL visual for depth %d\n", depth);
384 if (window_is_argb(w))
385 attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
387 attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
389 wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
394 glBindTexture(GL_TEXTURE_2D, wd->texname);
395 d->bind_func(w->sc->dpy->xlib_dpy,
396 wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
399 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
402 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
404 glBindTexture(GL_TEXTURE_2D, 0);
406 glxrender_update_window_region(w, wd);
410 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
412 xcb_xfixes_region_t reg;
413 xcb_xfixes_fetch_region_cookie_t ck;
414 xcb_xfixes_fetch_region_reply_t *rep;
415 xcb_rectangle_t area, *rects;
416 int nrects, i, x, y, wid, hei, bwid;
418 reg = window_get_region(w);
419 ck = xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn, reg);
421 window_get_area(w, &x, &y, &wid, &hei, &bwid);
424 area.width = wid + bwid * 2;
425 area.height = hei + bwid * 2;
427 rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, ck, NULL);
433 rects = xcb_xfixes_fetch_region_rectangles(rep);
434 nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
437 wd->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * (nrects * 4));
438 wd->vertices = (GLint*)malloc(sizeof(GLint) * (nrects * 4));
441 for (i = 0; i < nrects * 4; i += 4) {
442 wd->texcoords[i+LEFT] =
443 (GLfloat)(rects[i].x - area.x) / (GLfloat)area.width;
444 wd->texcoords[i+TOP] =
445 (GLfloat)(rects[i].y - area.y) / (GLfloat)area.height;
446 wd->texcoords[i+RIGHT] =
447 (GLfloat)(rects[i].x - area.x + rects[i].width) /
449 wd->texcoords[i+BOTTOM] =
450 (GLfloat)(rects[i].y - area.y + rects[i].height) /
451 (GLfloat)area.height;
453 wd->vertices[i+LEFT] = rects[i].x;
454 wd->vertices[i+TOP] = rects[i].y;
455 wd->vertices[i+RIGHT] = rects[i].x + rects[i].width;
456 wd->vertices[i+BOTTOM] = rects[i].y + rects[i].height;
464 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
467 static int attrs[] = {
468 GLX_TEXTURE_FORMAT_EXT,
469 GLX_TEXTURE_FORMAT_RGB_EXT,
473 px = screen_get_root_pixmap(sc);
476 if (!d->fbconfig[sc->super->root_depth]) {
477 printf("no GL visual for depth %d\n", sc->super->root_depth);
481 d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
482 d->fbconfig[sc->super->root_depth],
486 glBindTexture(GL_TEXTURE_2D, d->root_texname);
487 d->bind_func(sc->dpy->xlib_dpy,
488 d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
490 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
491 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
493 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
494 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
496 glBindTexture(GL_TEXTURE_2D, 0);
500 glxrender_window_resize(d_window_t *w)
505 d = screen_find_plugin_data(w->sc, plugin_id);
506 wd = window_find_plugin_data(w, plugin_id);
512 glxrender_free_window_pixmap(w, d, wd);
513 glxrender_update_window_pixmap(w, d, wd);
517 glxrender_window_move(d_window_t *w)
522 d = screen_find_plugin_data(w->sc, plugin_id);
523 wd = window_find_plugin_data(w, plugin_id);
529 glxrender_update_window_region(w, wd);
533 glxrender_window_reshape(d_window_t *w)
538 d = screen_find_plugin_data(w->sc, plugin_id);
539 wd = window_find_plugin_data(w, plugin_id);
542 d->window_reshape(w);
545 glxrender_free_window_pixmap(w, d, wd);
546 glxrender_update_window_pixmap(w, d, wd);
550 glxrender_root_pixmap_change(d_screen_t *sc)
554 d = screen_find_plugin_data(sc, plugin_id);
555 glxrender_free_root_pixmap(sc, d);
558 d->screen_root_pixmap_change(sc);
562 glxrender_paint(d_screen_t *sc)
564 data_t *d = screen_find_plugin_data(sc, plugin_id);
568 //printf("painting\n");
570 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
572 /* add 0.1f to keep everything above the root */
573 z = list_length(sc->stacking) * 0.1f + 0.1f;
574 for (it = list_top(sc->stacking); it; it = it->next) {
575 d_window_t *w = it->data;
577 if (!window_is_input_only(w) &&
578 (window_is_mapped(w) || window_is_zombie(w)))
580 int x, y, width, height, bwidth;
584 window_get_area(w, &x, &y, &width, &height, &bwidth);
586 if (!(x < sc->super->width_in_pixels &&
587 y < sc->super->height_in_pixels &&
588 (x + width > 0 || x + width + d->xshadowoff > 0) &&
589 (y + height > 0 || y + height + d->yshadowoff > 0)))
594 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
597 wd = window_find_plugin_data(w, plugin_id);
601 paint_window(w, d, wd, z + 0.05f);
613 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
615 for (it = list_bottom(sc->stacking); it; it = it->prev) {
616 d_window_t *w = it->data;
618 if (!window_is_input_only(w) &&
619 (window_is_mapped(w) || window_is_zombie(w)))
621 int x, y, width, height, bwidth;
627 window_get_area(w, &x, &y, &width, &height, &bwidth);
629 if (!(x < sc->super->width_in_pixels &&
630 y < sc->super->height_in_pixels &&
631 (x + width > 0 || x + width + d->xshadowoff > 0) &&
632 (y + height > 0 || y + height + d->yshadowoff > 0)))
637 opac = window_get_opacity(w);
638 opaque = !window_is_argb(w) && opac == 0xffff;
640 wd = window_find_plugin_data(w, plugin_id);
645 alpha = d->shadowalpha;
649 glColor4f(0.0f, 0.0f, 0.0f, alpha);
650 paint_shadow(d, wd, z);
654 glColor4us(opac, opac, opac, opac);
655 paint_window(w, d, wd, z + 0.05f);
664 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
665 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
668 //xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
669 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
671 /* call the function we replaced in the chain */
676 paint_root(d_screen_t *sc, data_t *d)
678 if (!d->root_glpixmap)
679 glxrender_update_root_pixmap(sc, d);
681 glBindTexture(GL_TEXTURE_2D, d->root_texname);
686 glVertex3i(sc->super->width_in_pixels, 0, 0);
688 glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
690 glVertex3i(0, sc->super->height_in_pixels, 0);
693 glBindTexture(GL_TEXTURE_2D, 0);
697 paint_window(d_window_t *w, data_t *d, window_data_t *wd, GLfloat z)
702 glxrender_update_window_pixmap(w, d, wd);
704 if (wd->nrects < 1) return;
706 glBindTexture(GL_TEXTURE_2D, wd->texname);
709 for (i = 0; i < wd->nrects * 4; i += 4) {
710 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
711 glVertex3f(wd->vertices[i+LEFT], wd->vertices[i+TOP], z);
712 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
713 glVertex3f(wd->vertices[i+RIGHT], wd->vertices[i+TOP], z);
714 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
715 glVertex3f(wd->vertices[i+RIGHT], wd->vertices[i+BOTTOM], z);
716 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
717 glVertex3f(wd->vertices[i+LEFT], wd->vertices[i+BOTTOM], z);
721 glBindTexture(GL_TEXTURE_2D, 0);
725 paint_shadow(data_t *d, window_data_t *wd, GLfloat z)
727 int xoff = d->xshadowoff;
728 int yoff = d->yshadowoff;
731 if (wd->nrects < 1) return;
733 /* shape the shadow to the window */
734 glBindTexture(GL_TEXTURE_2D, wd->texname);
737 for (i = 0; i < wd->nrects * 4; i += 4) {
738 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
739 glVertex3f(xoff+wd->vertices[i+LEFT], yoff+wd->vertices[i+TOP], z);
740 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
741 glVertex3f(xoff+wd->vertices[i+RIGHT], yoff+wd->vertices[i+TOP], z);
742 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
743 glVertex3f(xoff+wd->vertices[i+RIGHT], yoff+wd->vertices[i+BOTTOM], z);
744 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
745 glVertex3f(xoff+wd->vertices[i+LEFT], yoff+wd->vertices[i+BOTTOM], z);
749 glBindTexture(GL_TEXTURE_2D, 0);