Feature: OpenGL backend

- Add experimental OpenGL backend (--opengl). --blur-background is
  currently not possible with this backend, because I'm still trying to
  find a proper way to do blur with OpenGL. Flipping backend on-the-fly
  is really hard, so it isn't supported right now. No configuration file
  option exists to enable this, because it isn't stable enough.

- Add `opengl-swc` VSync method that uses SGI_swap_control to control
  buffer swap, with OpenGL backend. (#7)

- Fix a potential read-from-freed-memory issue in paint_all().

- Correctly reattach GLX context after fork.

- Dump error text in error(). Add GLX error code handling.

- Code clean-up.

- Known issues: Region operations take a lot of time in glx_render().
  I'm hesitating about what to do.
This commit is contained in:
Richard Grenville
2013-03-15 23:16:23 +08:00
parent 4bc3de81ab
commit 8ffcf1c1e8
7 changed files with 1183 additions and 424 deletions

View File

@ -9,7 +9,6 @@
#include "common.h"
#include <ctype.h>
#include <math.h>
#include <sys/select.h>
#include <limits.h>
@ -52,14 +51,6 @@ set_ignore_next(session_t *ps) {
static int
should_ignore(session_t *ps, unsigned long sequence);
/**
* Return the painting target window.
*/
static inline Window
get_tgt_window(session_t *ps) {
return ps->o.paint_on_overlay ? ps->overlay: ps->root;
}
/**
* Reset filter on a <code>Picture</code>.
*/
@ -119,16 +110,6 @@ array_wid_exists(const Window *arr, int count, Window wid) {
return false;
}
/**
* Destroy a <code>XserverRegion</code>.
*/
inline static void
free_region(session_t *ps, XserverRegion *p) {
if (*p) {
XFixesDestroyRegion(ps->dpy, *p);
*p = None;
}
}
/**
* Destroy a <code>Picture</code>.
@ -176,16 +157,58 @@ free_wincondlst(c2_lptr_t **pcondlst) {
}
#endif
/**
* Check whether a paint_t contains enough data.
*/
static inline bool
paint_isvalid(session_t *ps, const paint_t *ppaint) {
if (!ppaint || !ppaint->pixmap)
return false;
if (BKEND_XRENDER == ps->o.backend && !ppaint->pict)
return false;
#ifdef CONFIG_VSYNC_OPENGL
if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex))
return false;
#endif
return true;
}
/**
* Bind texture in paint_t if we are using OpenGL backend.
*/
static inline bool
paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int hei, int depth) {
#ifdef CONFIG_VSYNC_OPENGL
// TODO: Make sure we have the same Pixmap binded?
if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex)) {
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, depth);
}
#endif
return true;
}
/**
* Free paint_t.
*/
static inline void
free_paint(session_t *ps, paint_t *ppaint) {
free_texture(ps, &ppaint->ptex);
free_picture(ps, &ppaint->pict);
free_pixmap(ps, &ppaint->pixmap);
}
/**
* Destroy all resources in a <code>struct _win</code>.
*/
inline static void
static inline void
free_win_res(session_t *ps, win *w) {
free_region(ps, &w->extents);
free_pixmap(ps, &w->pixmap);
free_picture(ps, &w->picture);
free_paint(ps, &w->paint);
free_region(ps, &w->border_size);
free_picture(ps, &w->shadow_pict);
free_paint(ps, &w->shadow_paint);
free_damage(ps, &w->damage);
free_region(ps, &w->reg_ignore);
free(w->name);
@ -194,6 +217,19 @@ free_win_res(session_t *ps, win *w) {
free(w->role);
}
/**
* Free root tile related things.
*/
static inline void
free_root_tile(session_t *ps) {
free_picture(ps, &ps->root_tile_paint.pict);
free_texture(ps, &ps->root_tile_paint.ptex);
if (ps->root_tile_fill)
free_pixmap(ps, &ps->root_tile_paint.pixmap);
ps->root_tile_paint.pixmap = None;
ps->root_tile_fill = false;
}
/**
* Get current system clock in milliseconds.
*/
@ -274,8 +310,8 @@ presum_gaussian(session_t *ps, conv *map);
static XImage *
make_shadow(session_t *ps, double opacity, int width, int height);
static Picture
shadow_picture(session_t *ps, double opacity, int width, int height);
static bool
win_build_shadow(session_t *ps, win *w, double opacity);
static Picture
solid_picture(session_t *ps, bool argb, double a,
@ -463,11 +499,11 @@ group_is_focused(session_t *ps, Window leader) {
static win *
recheck_focus(session_t *ps);
static Picture
root_tile_f(session_t *ps);
static bool
get_root_tile(session_t *ps);
static void
paint_root(session_t *ps, Picture tgt_buffer);
paint_root(session_t *ps, XserverRegion reg_paint);
static XserverRegion
win_get_region(session_t *ps, win *w, bool use_offset);
@ -490,6 +526,22 @@ get_frame_extents(session_t *ps, win *w, Window client);
static win *
paint_preprocess(session_t *ps, win *list);
static void
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex, XserverRegion reg_paint);
static inline void
win_render(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, XserverRegion reg_paint, Picture pict) {
const int dx = (w ? w->a.x: 0) + x;
const int dy = (w ? w->a.y: 0) + y;
const bool argb = (w && w->mode == WMODE_ARGB);
const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg,
pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex), reg_paint);
}
static void
paint_all(session_t *ps, XserverRegion region, win *t);
@ -887,31 +939,7 @@ swopti_init(session_t *ps);
static void
swopti_handle_timeout(session_t *ps, struct timeval *ptv);
static bool
opengl_init(session_t *ps, bool need_render);
static void
opengl_destroy(session_t *ps);
#ifdef CONFIG_VSYNC_OPENGL
/**
* Check if a GLX extension exists.
*/
static inline bool
opengl_hasext(session_t *ps, const char *ext) {
const char *glx_exts = glXQueryExtensionsString(ps->dpy, ps->scr);
const char *pos = strstr(glx_exts, ext);
// Make sure the extension string is matched as a whole word
if (!pos
|| ((pos - glx_exts) && !isspace(*(pos - 1)))
|| (strlen(pos) > strlen(ext) && !isspace(pos[strlen(ext)]))) {
printf_errf("(): Missing OpenGL extension %s.", ext);
return false;
}
return true;
}
/**
* Ensure we have a GLX context.
*/
@ -919,7 +947,7 @@ static inline bool
ensure_glx_context(session_t *ps) {
// Create GLX context
if (!ps->glx_context)
opengl_init(ps, false);
glx_init(ps, false);
return ps->glx_context;
}
@ -939,6 +967,9 @@ vsync_opengl_init(session_t *ps);
static bool
vsync_opengl_oml_init(session_t *ps);
static bool
vsync_opengl_swc_init(session_t *ps);
#ifdef CONFIG_VSYNC_OPENGL
static int
vsync_opengl_wait(session_t *ps);