From 7ffde7ad754ceb4daebb3c8830f9a48dbf778688 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 9 Jun 2010 16:04:10 -0400 Subject: [PATCH] Basic compositing with GL --- openbox/composite.c | 302 ++++++++++++++++++++++++++++++++++++++++++-- openbox/composite.h | 47 +++++++ openbox/event.c | 15 +++ openbox/window.c | 36 ++++++ openbox/window.h | 13 ++ 5 files changed, 402 insertions(+), 11 deletions(-) diff --git a/openbox/composite.c b/openbox/composite.c index d33dc3ac..db355346 100644 --- a/openbox/composite.c +++ b/openbox/composite.c @@ -20,34 +20,246 @@ #include "composite.h" #include "config.h" #include "obt/display.h" +#include "openbox.h" +#include "screen.h" +#include "client.h" +#include "frame.h" +#include "geom.h" #include #include +#ifdef USE_COMPOSITING + +static gboolean composite(gpointer data); + +static struct ObCompositor obcomp; + +static inline void +time_fix(struct timeval *tv) +{ + while (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + ++tv->tv_sec; + } + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + --tv->tv_sec; + } +} + +static gboolean composite_need_redraw(void) +{ + return TRUE; +} + +static void get_best_fbcon(GLXFBConfig *in, int count, int depth, GLXFBConfig *out) +{ + GLXFBConfig best = 0; + XVisualInfo *vi; + int i, value, has_alpha; + + for (i = 0; i < count; i++) { + + vi = glXGetVisualFromFBConfig(obt_display, in[i]); + if (vi == NULL) + continue; + + value = vi->depth; + XFree(vi); + + if (value != depth) + continue; + + value = 0; + if (depth == 32) { + obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); + } + if (!value) { + obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &value); + } + if (!value) // neither bind to texture? no dice + continue; + best = in[i]; + } + *out = best; +} +#endif + void composite_startup(gboolean reconfig) { /* This function will try enable composite if config_comp is TRUE. At the end of this process, config_comp will be set to TRUE only if composite is enabled, and FALSE otherwise. */ #ifdef USE_COMPOSITING - gboolean try; + int count, val; + Time timestamp; + XWindowAttributes xa; + XserverRegion xr; + XVisualInfo tmp; + XVisualInfo *vi; + GLXFBConfig *fbcs; + const char *glstring; + gchar *astr; + Atom cm_atom; + Window cm_owner; + Window root; + int i; if (reconfig) return; - if (!(try = config_comp)) return; + if (!config_comp) return; config_comp = FALSE; - /* XXX test GL things we need also */ - if (!obt_display_extension_composite || - !obt_display_extension_damage || - !obt_display_extension_fixes) - { - try = FALSE; + root = RootWindow(obt_display, ob_screen); + + astr = g_strdup_printf("_NET_WM_CM_S%d", ob_screen); + cm_atom = XInternAtom(obt_display, astr, 0); + g_free(astr); + + cm_owner = XGetSelectionOwner(obt_display, cm_atom); + if (cm_owner != None) { + g_message("Failed to enable composite. There is already a compositor running."); + return; + } + + timestamp = event_time(); + XSetSelectionOwner(obt_display, cm_atom, screen_support_win, timestamp); + + if (XGetSelectionOwner(obt_display, cm_atom) != screen_support_win) { + g_message("Failed to enable composite. Could not acquire the composite manager selection on screen %d", ob_screen); + return; + } + + if (!obt_display_extension_composite) { + g_message("Failed to enable composite. The XComposite extension is missing."); + return; + } + + if (!obt_display_extension_damage) { + g_message("Failed to enable composite. The XDamage extension is missing."); + return; + } + + if (!obt_display_extension_fixes) { + g_message("Failed to enable composite. The XFixes extension is missing."); + return; + } + + glstring = glXQueryExtensionsString(obt_display, ob_screen); + if (!strstr(glstring, "GLX_EXT_texture_from_pixmap")) { + g_message("Failed to enable composite. GLX_EXT_texture_from_pixmap is not present."); + return; + } + + obcomp.CreatePixmap = (CreatePixmapT)glXGetProcAddress("glXCreatePixmap"); + if (!obcomp.CreatePixmap) { + g_message("Failed to enable composite. glXCreatePixmap unavailable."); + return; + } + + obcomp.BindTexImage = (BindTexImageT)glXGetProcAddress("glXBindTexImageEXT"); + if (!obcomp.BindTexImage) { + g_message("Failed to enable composite. glXBindTexImage unavailable."); + return; + } + + obcomp.ReleaseTexImage = (ReleaseTexImageT)glXGetProcAddress("glXReleaseTexImageEXT"); + if (!obcomp.ReleaseTexImage) { + g_message("Failed to enable composite. glXReleaseTexImage unavailable."); + return; } - config_comp = try; - if (!config_comp) - g_message("Failed to enable composite. A better explanation why would be nice"); + obcomp.GetFBConfigs = (GetFBConfigsT)glXGetProcAddress("glXGetFBConfigs"); + if (!obcomp.GetFBConfigs) { + g_message("Failed to enable composite. glXGetFBConfigs unavailable."); + return; + } + + obcomp.GetFBConfigAttrib = (GetFBConfigAttribT)glXGetProcAddress("glXGetFBConfigAttrib"); + if (!obcomp.GetFBConfigAttrib) { + g_message("Failed to enable composite. glXGetFBConfigAttrib unavailable."); + return; + } + + obcomp.overlay = XCompositeGetOverlayWindow(obt_display, root); +//now you've done it. better release this if we fail later! +//or move this get to the end? + + xr = XFixesCreateRegion(obt_display, NULL, 0); + XFixesSetWindowShapeRegion(obt_display, obcomp.overlay, ShapeBounding, 0, 0, 0); + XFixesSetWindowShapeRegion(obt_display, obcomp.overlay, ShapeInput, 0, 0, xr); + XFixesDestroyRegion(obt_display, xr); + + if (!XGetWindowAttributes(obt_display, root, &xa)) { + g_message("Failed to enable composite. XGetWindowAttributes failed."); + return; + } + + tmp.visualid = XVisualIDFromVisual(xa.visual); + vi = XGetVisualInfo(obt_display, VisualIDMask, &tmp, &count); + + if (!count) { + g_message("Failed to enable composite. Couldn't get visual info."); + return; + } + + + glXGetConfig(obt_display, vi, GLX_USE_GL, &val); + if (!val) { + g_message("Failed to enable composite. Visual is not GL capable"); + return; + } + + glXGetConfig(obt_display, vi, GLX_DOUBLEBUFFER, &val); + if (!val) { + g_message("Failed to enable composite. Visual is not double buffered"); + return; + } + + obcomp.ctx = glXCreateContext(obt_display, vi, NULL, True); + XFree(vi); + + fbcs = obcomp.GetFBConfigs(obt_display, ob_screen, &count); + + if (!count) { + g_message("Failed to enable composite. No valid FBConfigs."); + return; + } + + memset(&obcomp.PixmapConfig, 0, sizeof(obcomp.PixmapConfig)); + + for (i = 0; i < MAX_DEPTH + 1; i++) { + get_best_fbcon(fbcs, count, i, &obcomp.PixmapConfig[i]); + } + + if (count) + XFree(fbcs); + + printf("Best visual for 24bpp was 0x%x\n", obcomp.PixmapConfig[24]); + printf("Best visual for 32bpp was 0x%x\n", obcomp.PixmapConfig[32]); + + g_idle_add(composite, NULL); + + glXMakeCurrent(obt_display, obcomp.overlay, obcomp.ctx); + config_comp = TRUE; + obcomp.screendims = screen_physical_area_all_monitors(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glXSwapBuffers(obt_display, obcomp.overlay); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glOrtho(obcomp.screendims->x, + obcomp.screendims->x + obcomp.screendims->width, + obcomp.screendims->y + obcomp.screendims->height, + obcomp.screendims->y, + -100, 100); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif } @@ -57,3 +269,71 @@ void composite_shutdown(gboolean reconfig) if (reconfig) return; #endif } + +static gboolean composite(gpointer data) +{ +#ifdef USE_COMPOSITING + int attribs[] = { + GLX_TEXTURE_FORMAT_EXT, + None, + None + }; + struct timeval start, end, dif; + GList *it; + ObWindow *win; + ObClient *client; + static int i; + +// if (!obcomp.need_redraw) +// return; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +// for (it = stacking_list; it; it = g_list_next(it)) { + for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) { + win = it->data; + if (win->type != OB_WINDOW_CLASS_CLIENT) + continue; + + client = WINDOW_AS_CLIENT(win); + if (client->desktop != screen_desktop) + continue; + + if (win->depth == 32) + attribs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT; + else + attribs[1] = GLX_TEXTURE_FORMAT_RGB_EXT; + + if (win->gpixmap == None) + win->gpixmap = obcomp.CreatePixmap(obt_display, obcomp.PixmapConfig[win->depth], win->pixmap, attribs); + + glBindTexture(GL_TEXTURE_2D, win->texture); +gettimeofday(&start, NULL); + obcomp.BindTexImage(obt_display, win->gpixmap, GLX_FRONT_LEFT_EXT, NULL); +gettimeofday(&end, NULL); +dif.tv_sec = end.tv_sec - start.tv_sec; +dif.tv_usec = end.tv_usec - start.tv_usec; +time_fix(&dif); +//printf("took %f ms\n", dif.tv_sec * 1000.0 + dif.tv_usec / 1000.0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex3f(client->frame->area.x, client->frame->area.y, 0.0); + glTexCoord2f(0, 1); + glVertex3f(client->frame->area.x, client->frame->area.y + client->frame->area.height, 0.0); + glTexCoord2f(1, 1); + glVertex3f(client->frame->area.x + client->frame->area.width, client->frame->area.y + client->frame->area.height, 0.0); + glTexCoord2f(1, 0); + glVertex3f(client->frame->area.x + client->frame->area.width, client->frame->area.y, 0.0); + glEnd(); + } + glXSwapBuffers(obt_display, obcomp.overlay); + glFinish(); + obcomp.need_redraw = 0; +#endif + return TRUE; +} diff --git a/openbox/composite.h b/openbox/composite.h index 6b03cadc..01b02d86 100644 --- a/openbox/composite.h +++ b/openbox/composite.h @@ -20,7 +20,54 @@ #ifndef __composite_h #define __composite_h +#ifdef USE_COMPOSITING #include +#include +#include + +#include "geom.h" + +#define MAX_DEPTH 32 + +typedef GLXPixmap (*CreatePixmapT)(Display *display, + GLXFBConfig config, + int attribute, + int *value); + +typedef void (*BindTexImageT)(Display *display, + GLXDrawable drawable, + int buffer, + int *attriblist); + +typedef void (*ReleaseTexImageT)(Display *display, + GLXDrawable drawable, + int buffer); + +typedef GLXFBConfig *(*GetFBConfigsT) (Display *display, + int screen, + int *nElements); + +typedef int (*GetFBConfigAttribT) (Display *display, + GLXFBConfig config, + int attribute, + int *value); + +struct ObCompositor { + CreatePixmapT CreatePixmap; + BindTexImageT BindTexImage; + ReleaseTexImageT ReleaseTexImage; + GetFBConfigsT GetFBConfigs; + GetFBConfigAttribT GetFBConfigAttrib; + + Window overlay; + + GLXContext ctx; + GLXFBConfig PixmapConfig[MAX_DEPTH + 1]; // need a [32] + + gboolean need_redraw; + const Rect *screendims; +}; +#endif void composite_startup(gboolean reconfig); void composite_shutdown(gboolean reconfig); diff --git a/openbox/event.c b/openbox/event.c index 46e569bf..3fba27f6 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -621,6 +621,21 @@ static void event_process(const XEvent *ec, gpointer data) if (client && client != focus_client) frame_adjust_focus(client->frame, FALSE); } +#ifdef USE_COMPOSITING + else if ((e->type == ConfigureNotify || e->type == MapNotify) + && obwin && obwin->type != OB_WINDOW_CLASS_PROMPT) { + if (obwin->pixmap != None) + XFreePixmap(obt_display, obwin->pixmap); + obwin->pixmap = XCompositeNameWindowPixmap(obt_display, window_top(obwin)); + if (obwin->gpixmap != None) { + XFreePixmap(obt_display, obwin->gpixmap); + obwin->gpixmap = None; + } + +//XXX actually need to check if this was just a move and not re-make the pmap! +//printf("win %d has pixmap %d\n", window_top(obwin), obwin->pixmap); + } +#endif else if (client) event_handle_client(client, e); else if (dockapp) diff --git a/openbox/window.c b/openbox/window.c index ad61294d..f28bd43e 100644 --- a/openbox/window.c +++ b/openbox/window.c @@ -94,12 +94,48 @@ void window_add(Window *xwin, ObWindow *win) { g_assert(xwin != NULL); g_assert(win != NULL); +#ifdef USE_COMPOSITING + XWindowAttributes wattrib; + Status ret; + + if (win->type != OB_WINDOW_CLASS_PROMPT) { + win->damage = XDamageCreate(obt_display, window_top(win), XDamageReportNonEmpty); + + XCompositeRedirectWindow(obt_display, window_top(win), CompositeRedirectManual); + + win->pixmap = None; + glGenTextures(1, &win->texture); + ret = XGetWindowAttributes(obt_display, window_top(win), &wattrib); + g_assert(ret != BadDrawable); + g_assert(ret != BadWindow); + + win->depth = wattrib.depth; + } +#endif g_hash_table_insert(window_map, xwin, win); } void window_remove(Window xwin) { g_assert(xwin != None); +#ifdef USE_COMPOSITING + ObWindow *win; + win = window_find(xwin); + if (!win) { + printf("Compositor tried to clean up a window, but it was not there.\n"); + return; + } + if (win->type != OB_WINDOW_CLASS_PROMPT) { + if (win->damage) + XDamageDestroy(obt_display, win->damage); + if (win->gpixmap) + XFreePixmap(obt_display, win->gpixmap); + if (win->pixmap) + XFreePixmap(obt_display, win->pixmap); + if (win->texture) + glDeleteTextures(1, &win->texture); + } +#endif g_hash_table_remove(window_map, &xwin); } diff --git a/openbox/window.h b/openbox/window.h index 24a7d07b..9883554d 100644 --- a/openbox/window.h +++ b/openbox/window.h @@ -24,6 +24,12 @@ #include #include +#ifdef USE_COMPOSITING +#include +#include +#include +#endif + typedef struct _ObWindow ObWindow; typedef struct _ObInternalWindow ObInternalWindow; @@ -39,6 +45,13 @@ typedef enum { struct */ struct _ObWindow { ObWindowClass type; +#ifdef USE_COMPOSITING + GLuint texture; + Pixmap pixmap; + GLXPixmap gpixmap; + Damage damage; + int depth; +#endif }; #define WINDOW_IS_MENUFRAME(win) \ -- 2.39.2