14 #include <GL/glxproto.h>
18 #include <GL/glxtokens.h>
20 #include <GL/glxext.h>
31 typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *);
32 typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int);
35 void (*screen_paint)(d_screen_t *sc);
36 void (*screen_root_pixmap_change)(d_screen_t *sc);
37 void (*window_show)(d_window_t *w);
38 void (*window_zombie_dead)(d_window_t *w);
39 void (*window_resize)(d_window_t *w);
40 void (*window_reshape)(d_window_t *w);
46 GLXFBConfig fbconfig[MAX_DEPTH + 1];
50 GLXPixmap root_glpixmap;
52 BindEXTFunc bind_func;
53 ReleaseEXTFunc release_func;
64 xcb_xfixes_fetch_region_cookie_t ck_region;
73 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
75 static void glxrender_paint(d_screen_t *sc);
76 static void glxrender_root_pixmap_change(d_screen_t *sc);
77 static void paint_root(d_screen_t *sc, data_t *d);
78 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
79 int x, int y, GLfloat z);
80 static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
82 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
84 static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
85 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
86 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
88 static void glxrender_free_window_region(window_data_t *wd);
89 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
90 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
92 static void glxrender_window_show(d_window_t *window);
93 static void glxrender_window_zombie_dead(d_window_t *window);
94 static void glxrender_window_resize(d_window_t *window);
95 static void glxrender_window_reshape(d_window_t *window);
98 glxrender_init(d_screen_t *sc, int id)
100 static int context_visual_config[] = {
111 d = malloc(sizeof(data_t));
112 d->screen_paint = sc->screen_paint;
113 d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
114 d->window_show = sc->window_show;
115 d->window_zombie_dead = sc->window_zombie_dead;
116 d->window_resize = sc->window_resize;
117 d->window_reshape = sc->window_reshape;
118 screen_add_plugin_data(sc, plugin_id, d);
120 sc->screen_paint = glxrender_paint;
121 sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
122 sc->window_show = glxrender_window_show;
123 sc->window_zombie_dead = glxrender_window_zombie_dead;
124 sc->window_resize = glxrender_window_resize;
125 sc->window_reshape = glxrender_window_reshape;
127 d->shadowalpha = 0.2f; /* 20% */
131 vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
133 printf("unable to find a valid double buffered GL context to use\n");
137 if (!(glxrender_find_fb_config(sc, d))) {
138 printf("unable to find FB configs\n");
142 d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
143 glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
145 glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
146 glMatrixMode(GL_PROJECTION);
148 glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
150 glMatrixMode(GL_MODELVIEW);
152 glEnable(GL_TEXTURE_2D);
153 glEnable(GL_DEPTH_TEST);
154 //glEnable(GL_SCISSOR_TEST); ?? what is this, glxcompmgr enables it
155 //glEnable(GL_STENCIL_TEST); ?? what is this, glxcompmgr enables it
157 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
158 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
161 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
162 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
164 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
166 d->bind_func = (BindEXTFunc)
167 glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
168 d->release_func = (ReleaseEXTFunc)
169 glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
171 glGenTextures(1, &d->root_texname);
172 d->root_glpixmap = XCB_NONE;
176 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
178 static const int drawable_tfp_attrs[] = {
179 GLX_CONFIG_CAVEAT, GLX_NONE,
180 GLX_DOUBLEBUFFER, FALSE,
186 GLX_RENDER_TYPE, GLX_RGBA_BIT,
187 GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
190 int db, stencil, depth, numfb, i;
192 XVisualInfo tvis, *visinfo;
194 fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
195 drawable_tfp_attrs, &numfb);
196 if (!fbcons) return FALSE;
198 for (i = 0; i <= MAX_DEPTH; i++) {
208 //printf("looking for depth %d\n", i);
211 visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
213 /* pick the nicest visual for the depth */
214 for (j = 0; j < count; j++) {
215 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
219 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
225 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
231 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
237 /* use this visual */
238 vid = visinfo[j].visualid;
243 /* look for an fbconfig for this visual */
244 for (j = 0; j < numfb; ++j) {
245 glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
246 GLX_VISUAL_ID, &value);
247 if ((unsigned)value == vid) {
248 d->fbconfig[i] = fbcons[j];
250 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
251 (uint32_t)vid, (uint32_t)fbcons[j], i);
262 glxrender_free(d_screen_t *sc)
264 data_t *d = screen_find_plugin_data(sc, plugin_id);
266 glxrender_free_root_pixmap(sc, d);
267 glXDestroyContext(sc->dpy->xlib_dpy, d->context);
270 screen_remove_plugin_data(sc, plugin_id);
274 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
282 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
288 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
290 glxrender_free_window_pixmap(w, d, wd);
291 glxrender_free_window_region(wd);
292 glDeleteTextures(1, &wd->texname);
297 glxrender_window_show(d_window_t *w)
302 d = screen_find_plugin_data(w->sc, plugin_id);
307 wd = window_find_plugin_data(w, plugin_id);
309 glxrender_window_free_data(w, d, wd);
311 wd = malloc(sizeof(window_data_t));
312 glGenTextures(1, &wd->texname);
313 wd->glpixmap = XCB_NONE;
314 wd->texcoords = NULL;
317 wd->waiting_region = FALSE;
319 window_add_plugin_data(w, plugin_id, wd);
321 glxrender_fetch_window_region(w, wd);
325 glxrender_window_zombie_dead(d_window_t *w)
330 d = screen_find_plugin_data(w->sc, plugin_id);
331 wd = window_find_plugin_data(w, plugin_id);
333 glxrender_window_free_data(w, d, wd);
334 window_remove_plugin_data(w, plugin_id);
338 d->window_zombie_dead(w);
342 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
344 /* this might cause an error, oh well */
346 glBindTexture(GL_TEXTURE_2D, wd->texname);
347 d->release_func(w->sc->dpy->xlib_dpy,
348 wd->glpixmap, GLX_FRONT_LEFT_EXT);
349 glBindTexture(GL_TEXTURE_2D, 0);
351 glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
352 wd->glpixmap = XCB_NONE;
358 glxrender_free_window_region(window_data_t *wd)
363 wd->texcoords = NULL;
370 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
372 /* this might cause an error, oh well */
373 if (d->root_glpixmap) {
374 glBindTexture(GL_TEXTURE_2D, d->root_texname);
375 d->release_func(sc->dpy->xlib_dpy,
376 d->root_glpixmap, GLX_FRONT_LEFT_EXT);
377 glBindTexture(GL_TEXTURE_2D, 0);
379 glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
380 d->root_glpixmap = XCB_NONE;
385 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
390 static int attrs[] = {
391 GLX_TEXTURE_FORMAT_EXT,
396 px = window_get_pixmap(w);
397 depth = window_get_depth(w);
401 if (!d->fbconfig[depth]) {
402 printf("no GL visual for depth %d\n", depth);
406 if (window_is_argb(w))
407 attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
409 attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
411 wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
415 wd->glpixmap = xcb_generate_id(w->sc->dpy->conn);
417 glXGetFBConfigAttrib(w->sc->dpy->xlib_dpy, d->fbconfig[depth],
418 GLX_FBCONFIG_ID, &v);
419 xcb_void_cookie_t ck =
420 xcb_glx_create_pixmap_checked(w->sc->dpy->conn, w->sc->num,
425 xcb_generic_error_t *err = xcb_request_check(w->sc->dpy->conn, ck);
427 display_error(w->sc->dpy, err);
429 wd->glpixmap = XCB_NONE;
434 glBindTexture(GL_TEXTURE_2D, wd->texname);
435 d->bind_func(w->sc->dpy->xlib_dpy,
436 wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
441 1 CARD8 opcode (X assigned)
442 1 16 GLX opcode (glXVendorPrivate)
444 4 1330 vendor specific opcode
446 4 GLX_DRAWABLE drawable
448 4 CARD32 num_attributes
449 4*n LISTofATTRIBUTE_PAIR attribute, value pairs.
451 unsigned int len = 12;
457 xcb_glx_vendor_private(w->sc->dpy->conn,
458 X_GLXvop_BindTexImageEXT,
460 len, (uint8_t*)data);
464 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
465 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
470 glBindTexture(GL_TEXTURE_2D, 0);
474 glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
476 window_get_area(w, &wd->x_region, &wd->y_region,
477 &wd->w_region, &wd->h_region, &wd->bw_region);
480 xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
481 window_get_region(w));
482 wd->waiting_region = TRUE;
483 xcb_flush(w->sc->dpy->conn);
487 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
489 xcb_xfixes_fetch_region_reply_t *rep;
490 xcb_rectangle_t area, *rects;
493 if (!wd->waiting_region) return;
495 area.x = wd->x_region;
496 area.y = wd->y_region;
497 area.width = wd->w_region + wd->bw_region * 2;
498 area.height = wd->h_region + wd->bw_region * 2;
500 rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
506 rects = xcb_xfixes_fetch_region_rectangles(rep);
507 nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
510 wd->texcoords = (GLfloat*)realloc(wd->texcoords,
511 sizeof(GLfloat) * (nrects * 4));
512 wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
515 for (i = j = 0; i < nrects * 4; ++j, i += 4) {
516 wd->texcoords[i+LEFT] =
517 (GLfloat)(rects[j].x - area.x) / (GLfloat)area.width;
518 wd->texcoords[i+TOP] =
519 (GLfloat)(rects[j].y - area.y) / (GLfloat)area.height;
520 wd->texcoords[i+RIGHT] =
521 (GLfloat)(rects[j].x - area.x + rects[j].width) /
523 wd->texcoords[i+BOTTOM] =
524 (GLfloat)(rects[j].y - area.y + rects[j].height) /
525 (GLfloat)area.height;
527 wd->vertices[i+LEFT] = rects[j].x - area.x;
528 wd->vertices[i+TOP] = rects[j].y - area.y;
529 wd->vertices[i+RIGHT] = rects[j].x - area.x + rects[j].width;
530 wd->vertices[i+BOTTOM] = rects[j].y - area.y + rects[j].height;
536 wd->waiting_region = FALSE;
540 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
543 static int attrs[] = {
544 GLX_TEXTURE_FORMAT_EXT,
545 GLX_TEXTURE_FORMAT_RGB_EXT,
549 px = screen_get_root_pixmap(sc);
552 if (!d->fbconfig[sc->super->root_depth]) {
553 printf("no GL visual for depth %d\n", sc->super->root_depth);
557 d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
558 d->fbconfig[sc->super->root_depth],
562 glBindTexture(GL_TEXTURE_2D, d->root_texname);
563 d->bind_func(sc->dpy->xlib_dpy,
564 d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
566 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
567 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
569 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
572 glBindTexture(GL_TEXTURE_2D, 0);
576 glxrender_window_resize(d_window_t *w)
581 d = screen_find_plugin_data(w->sc, plugin_id);
582 wd = window_find_plugin_data(w, plugin_id);
588 glxrender_free_window_pixmap(w, d, wd);
589 glxrender_fetch_window_region(w, wd);
593 glxrender_window_reshape(d_window_t *w)
598 d = screen_find_plugin_data(w->sc, plugin_id);
599 wd = window_find_plugin_data(w, plugin_id);
602 d->window_reshape(w);
605 glxrender_free_window_pixmap(w, d, wd);
606 glxrender_fetch_window_region(w, wd);
610 glxrender_root_pixmap_change(d_screen_t *sc)
614 d = screen_find_plugin_data(sc, plugin_id);
615 glxrender_free_root_pixmap(sc, d);
618 d->screen_root_pixmap_change(sc);
622 glxrender_paint(d_screen_t *sc)
624 data_t *d = screen_find_plugin_data(sc, plugin_id);
628 //printf("painting\n");
630 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
632 /* add 0.1f to keep everything above the root */
633 z = list_length(sc->stacking) * 0.1f + 0.1f;
634 for (it = list_top(sc->stacking); it; it = it->next) {
635 d_window_t *w = it->data;
637 if (!window_is_input_only(w) &&
638 (window_is_mapped(w) || window_is_zombie(w)))
640 int x, y, width, height, bwidth;
644 window_get_area(w, &x, &y, &width, &height, &bwidth);
646 if (!(x < sc->super->width_in_pixels &&
647 y < sc->super->height_in_pixels &&
648 (x + width > 0 || x + width + d->xshadowoff > 0) &&
649 (y + height > 0 || y + height + d->yshadowoff > 0)))
654 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
657 wd = window_find_plugin_data(w, plugin_id);
661 paint_window(w, d, wd, x, y, z - 0.05f);
673 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
675 for (it = list_bottom(sc->stacking); it; it = it->prev) {
676 d_window_t *w = it->data;
678 if (!window_is_input_only(w) &&
679 (window_is_mapped(w) || window_is_zombie(w)))
681 int x, y, width, height, bwidth;
687 window_get_area(w, &x, &y, &width, &height, &bwidth);
689 if (!(x < sc->super->width_in_pixels &&
690 y < sc->super->height_in_pixels &&
691 (x + width > 0 || x + width + d->xshadowoff > 0) &&
692 (y + height > 0 || y + height + d->yshadowoff > 0)))
697 opac = window_get_opacity(w);
698 opaque = !window_is_argb(w) && opac == 0xffff;
700 wd = window_find_plugin_data(w, plugin_id);
705 alpha = d->shadowalpha;
709 glColor4f(0.0f, 0.0f, 0.0f, alpha);
710 paint_shadow(d, wd, x, y, z);
714 glColor4us(opac, opac, opac, opac);
715 paint_window(w, d, wd, x, y, z + 0.05f);
724 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
725 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
728 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
730 /* call the function we replaced in the chain */
735 paint_root(d_screen_t *sc, data_t *d)
737 if (!d->root_glpixmap)
738 glxrender_update_root_pixmap(sc, d);
740 glBindTexture(GL_TEXTURE_2D, d->root_texname);
745 glVertex3i(sc->super->width_in_pixels, 0, 0);
747 glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
749 glVertex3i(0, sc->super->height_in_pixels, 0);
752 glBindTexture(GL_TEXTURE_2D, 0);
756 paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
762 glxrender_update_window_pixmap(w, d, wd);
763 if (wd->waiting_region)
764 glxrender_update_window_region(w, wd);
766 if (wd->nrects < 1) return;
768 glBindTexture(GL_TEXTURE_2D, wd->texname);
771 for (i = 0; i < wd->nrects * 4; i += 4) {
772 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
773 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
774 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
775 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
776 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
777 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
778 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
779 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
783 glBindTexture(GL_TEXTURE_2D, 0);
787 paint_shadow(data_t *d, window_data_t *wd, int x, int y, GLfloat z)
791 if (wd->nrects < 1) return;
793 /* shape the shadow to the window */
794 glBindTexture(GL_TEXTURE_2D, wd->texname);
800 for (i = 0; i < wd->nrects * 4; i += 4) {
801 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
802 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
803 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
804 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
805 glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
806 glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
807 glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
808 glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
812 glBindTexture(GL_TEXTURE_2D, 0);