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;
70 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
72 static void glxrender_paint(d_screen_t *sc);
73 static void glxrender_root_pixmap_change(d_screen_t *sc);
74 static void paint_root(d_screen_t *sc, data_t *d);
75 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
76 int x, int y, GLfloat z);
77 static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
79 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
81 static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
82 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
83 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
85 static void glxrender_free_window_region(window_data_t *wd);
86 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
87 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
89 static void glxrender_window_show(d_window_t *window);
90 static void glxrender_window_zombie_dead(d_window_t *window);
91 static void glxrender_window_resize(d_window_t *window);
92 static void glxrender_window_reshape(d_window_t *window);
95 glxrender_init(d_screen_t *sc, int id)
97 static int context_visual_config[] = {
108 d = malloc(sizeof(data_t));
109 d->screen_paint = sc->screen_paint;
110 d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
111 d->window_show = sc->window_show;
112 d->window_zombie_dead = sc->window_zombie_dead;
113 d->window_resize = sc->window_resize;
114 d->window_reshape = sc->window_reshape;
115 screen_add_plugin_data(sc, plugin_id, d);
117 sc->screen_paint = glxrender_paint;
118 sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
119 sc->window_show = glxrender_window_show;
120 sc->window_zombie_dead = glxrender_window_zombie_dead;
121 sc->window_resize = glxrender_window_resize;
122 sc->window_reshape = glxrender_window_reshape;
124 d->shadowalpha = 0.2f; /* 20% */
128 vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
130 printf("unable to find a valid double buffered GL context to use\n");
134 d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
135 glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
138 if (!(glxrender_find_fb_config(sc, d))) {
139 printf("unable to find FB configs\n");
143 glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
144 glMatrixMode(GL_PROJECTION);
146 glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
148 glMatrixMode(GL_MODELVIEW);
150 glEnable(GL_TEXTURE_2D);
151 glEnable(GL_DEPTH_TEST);
153 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
154 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
157 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
158 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
159 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
161 d->bind_func = (BindEXTFunc)
162 glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
163 d->release_func = (ReleaseEXTFunc)
164 glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
166 glGenTextures(1, &d->root_texname);
167 d->root_glpixmap = XCB_NONE;
171 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
173 static const int drawable_tfp_attrs[] = {
174 GLX_CONFIG_CAVEAT, GLX_NONE,
175 GLX_DOUBLEBUFFER, FALSE,
181 GLX_RENDER_TYPE, GLX_RGBA_BIT,
182 GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
185 int db, stencil, depth, numfb, i;
187 XVisualInfo tvis, *visinfo;
189 fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
190 drawable_tfp_attrs, &numfb);
191 if (!fbcons) return FALSE;
193 for (i = 0; i <= MAX_DEPTH; i++) {
203 printf("looking for depth %d\n", i);
206 visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
208 /* pick the nicest visual for the depth */
209 for (j = 0; j < count; j++) {
210 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
214 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
220 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
226 glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
232 /* use this visual */
233 vid = visinfo[j].visualid;
238 /* look for an fbconfig for this visual */
239 for (j = 0; j < numfb; ++j) {
240 glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
241 GLX_VISUAL_ID, &value);
242 if ((unsigned)value == vid) {
243 d->fbconfig[i] = fbcons[j];
245 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
246 (uint32_t)vid, (uint32_t)fbcons[j], i);
257 glxrender_free(d_screen_t *sc)
259 data_t *d = screen_find_plugin_data(sc, plugin_id);
261 glxrender_free_root_pixmap(sc, d);
264 screen_remove_plugin_data(sc, plugin_id);
268 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
276 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
282 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
284 glxrender_free_window_pixmap(w, d, wd);
285 glxrender_free_window_region(wd);
286 glDeleteTextures(1, &wd->texname);
291 glxrender_window_show(d_window_t *w)
296 d = screen_find_plugin_data(w->sc, plugin_id);
301 wd = window_find_plugin_data(w, plugin_id);
303 glxrender_window_free_data(w, d, wd);
305 wd = malloc(sizeof(window_data_t));
306 glGenTextures(1, &wd->texname);
307 wd->glpixmap = XCB_NONE;
308 wd->texcoords = NULL;
311 wd->waiting_region = FALSE;
313 window_add_plugin_data(w, plugin_id, wd);
315 glxrender_fetch_window_region(w, wd);
319 glxrender_window_zombie_dead(d_window_t *w)
324 d = screen_find_plugin_data(w->sc, plugin_id);
325 wd = window_find_plugin_data(w, plugin_id);
327 glxrender_window_free_data(w, d, wd);
328 window_remove_plugin_data(w, plugin_id);
332 d->window_zombie_dead(w);
336 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
338 /* this might cause an error, oh well */
340 glBindTexture(GL_TEXTURE_2D, wd->texname);
341 d->release_func(w->sc->dpy->xlib_dpy,
342 wd->glpixmap, GLX_FRONT_LEFT_EXT);
343 glBindTexture(GL_TEXTURE_2D, 0);
345 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
346 glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
347 wd->glpixmap = XCB_NONE;
353 glxrender_free_window_region(window_data_t *wd)
358 wd->texcoords = NULL;
365 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
367 /* this might cause an error, oh well */
368 if (d->root_glpixmap) {
369 glBindTexture(GL_TEXTURE_2D, d->root_texname);
370 d->release_func(sc->dpy->xlib_dpy,
371 d->root_glpixmap, GLX_FRONT_LEFT_EXT);
372 glBindTexture(GL_TEXTURE_2D, 0);
374 //xcb_glx_destroy_pixmap(w->sc->dpy->conn, wd->glpixmap);
375 glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
376 d->root_glpixmap = XCB_NONE;
381 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
386 static int attrs[] = {
387 GLX_TEXTURE_FORMAT_EXT,
392 px = window_get_pixmap(w);
393 depth = window_get_depth(w);
397 if (!d->fbconfig[depth]) {
398 printf("no GL visual for depth %d\n", depth);
402 if (window_is_argb(w))
403 attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
405 attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
407 wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
411 glBindTexture(GL_TEXTURE_2D, wd->texname);
412 d->bind_func(w->sc->dpy->xlib_dpy,
413 wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
415 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
418 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
419 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
421 glBindTexture(GL_TEXTURE_2D, 0);
425 glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
427 window_get_area(w, &wd->x_region, &wd->y_region,
428 &wd->w_region, &wd->h_region, &wd->bw_region);
431 xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
432 window_get_region(w));
433 wd->waiting_region = TRUE;
434 xcb_flush(w->sc->dpy->conn);
438 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
440 xcb_xfixes_fetch_region_reply_t *rep;
441 xcb_rectangle_t area, *rects;
444 if (!wd->waiting_region) return;
446 area.x = wd->x_region;
447 area.y = wd->y_region;
448 area.width = wd->w_region + wd->bw_region * 2;
449 area.height = wd->h_region + wd->bw_region * 2;
451 rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
457 rects = xcb_xfixes_fetch_region_rectangles(rep);
458 nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
461 wd->texcoords = (GLfloat*)realloc(wd->texcoords,
462 sizeof(GLfloat) * (nrects * 4));
463 wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
466 for (i = j = 0; i < nrects * 4; ++j, i += 4) {
467 wd->texcoords[i+LEFT] =
468 (GLfloat)(rects[j].x - area.x) / (GLfloat)area.width;
469 wd->texcoords[i+TOP] =
470 (GLfloat)(rects[j].y - area.y) / (GLfloat)area.height;
471 wd->texcoords[i+RIGHT] =
472 (GLfloat)(rects[j].x - area.x + rects[j].width) /
474 wd->texcoords[i+BOTTOM] =
475 (GLfloat)(rects[j].y - area.y + rects[j].height) /
476 (GLfloat)area.height;
478 wd->vertices[i+LEFT] = rects[j].x - area.x;
479 wd->vertices[i+TOP] = rects[j].y - area.y;
480 wd->vertices[i+RIGHT] = rects[j].x - area.x + rects[j].width;
481 wd->vertices[i+BOTTOM] = rects[j].y - area.y + rects[j].height;
487 wd->waiting_region = FALSE;
491 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
494 static int attrs[] = {
495 GLX_TEXTURE_FORMAT_EXT,
496 GLX_TEXTURE_FORMAT_RGB_EXT,
500 px = screen_get_root_pixmap(sc);
503 if (!d->fbconfig[sc->super->root_depth]) {
504 printf("no GL visual for depth %d\n", sc->super->root_depth);
508 d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
509 d->fbconfig[sc->super->root_depth],
513 glBindTexture(GL_TEXTURE_2D, d->root_texname);
514 d->bind_func(sc->dpy->xlib_dpy,
515 d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
517 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
518 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
520 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
521 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
523 glBindTexture(GL_TEXTURE_2D, 0);
527 glxrender_window_resize(d_window_t *w)
532 d = screen_find_plugin_data(w->sc, plugin_id);
533 wd = window_find_plugin_data(w, plugin_id);
539 glxrender_free_window_pixmap(w, d, 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);
557 glxrender_fetch_window_region(w, wd);
561 glxrender_root_pixmap_change(d_screen_t *sc)
565 d = screen_find_plugin_data(sc, plugin_id);
566 glxrender_free_root_pixmap(sc, d);
569 d->screen_root_pixmap_change(sc);
573 glxrender_paint(d_screen_t *sc)
575 data_t *d = screen_find_plugin_data(sc, plugin_id);
579 //printf("painting\n");
581 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
583 /* add 0.1f to keep everything above the root */
584 z = list_length(sc->stacking) * 0.1f + 0.1f;
585 for (it = list_top(sc->stacking); it; it = it->next) {
586 d_window_t *w = it->data;
588 if (!window_is_input_only(w) &&
589 (window_is_mapped(w) || window_is_zombie(w)))
591 int x, y, width, height, bwidth;
595 window_get_area(w, &x, &y, &width, &height, &bwidth);
597 if (!(x < sc->super->width_in_pixels &&
598 y < sc->super->height_in_pixels &&
599 (x + width > 0 || x + width + d->xshadowoff > 0) &&
600 (y + height > 0 || y + height + d->yshadowoff > 0)))
605 opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
608 wd = window_find_plugin_data(w, plugin_id);
612 paint_window(w, d, wd, x, y, z - 0.05f);
624 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
626 for (it = list_bottom(sc->stacking); it; it = it->prev) {
627 d_window_t *w = it->data;
629 if (!window_is_input_only(w) &&
630 (window_is_mapped(w) || window_is_zombie(w)))
632 int x, y, width, height, bwidth;
638 window_get_area(w, &x, &y, &width, &height, &bwidth);
640 if (!(x < sc->super->width_in_pixels &&
641 y < sc->super->height_in_pixels &&
642 (x + width > 0 || x + width + d->xshadowoff > 0) &&
643 (y + height > 0 || y + height + d->yshadowoff > 0)))
648 opac = window_get_opacity(w);
649 opaque = !window_is_argb(w) && opac == 0xffff;
651 wd = window_find_plugin_data(w, plugin_id);
656 alpha = d->shadowalpha;
660 glColor4f(0.0f, 0.0f, 0.0f, alpha);
661 paint_shadow(d, wd, x, y, z);
665 glColor4us(opac, opac, opac, opac);
666 paint_window(w, d, wd, x, y, z + 0.05f);
675 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
676 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
679 //xcb_glx_swap_buffers(sc->dpy->conn, d->context_tag, sc->overlay);
680 glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
682 /* call the function we replaced in the chain */
687 paint_root(d_screen_t *sc, data_t *d)
689 if (!d->root_glpixmap)
690 glxrender_update_root_pixmap(sc, d);
692 glBindTexture(GL_TEXTURE_2D, d->root_texname);
697 glVertex3i(sc->super->width_in_pixels, 0, 0);
699 glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
701 glVertex3i(0, sc->super->height_in_pixels, 0);
704 glBindTexture(GL_TEXTURE_2D, 0);
708 paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
714 glxrender_update_window_pixmap(w, d, wd);
715 if (wd->waiting_region)
716 glxrender_update_window_region(w, 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);