Bug fix #91: Using pkg-config to find drm.h & OpenGL changes

- #91: Use pkg-config to find drm.h to avoid issues on FreeBSD. Thanks
  to hun7err for pointing out and providing patch.

- #89: Add default shadow exclusion rule for notify-osd. Thanks to
  DanielRS.

- Check for abundant positional arguments.

- Use paint target window (root window / overlay window) instead of
  ps->reg_win to create GLXContext. (May have negative effects on OpenGL
  VSync.) Add new OpenGL helpers functions, to prepare for the new
  OpenGL backend.

- Dump more info of a PropertyNotify with DEBUG_EVENTS.
This commit is contained in:
Richard Grenville 2013-03-01 12:41:16 +08:00
parent 218250546e
commit e3eca7ac61
5 changed files with 236 additions and 97 deletions

View File

@ -38,6 +38,7 @@ endif
# ==== DRM VSync ====
ifeq "$(NO_VSYNC_DRM)" ""
INCS += $(shell pkg-config --cflags libdrm)
CFG += -DCONFIG_VSYNC_DRM
endif

View File

@ -10,7 +10,7 @@ shadow-offset-y = -7;
# shadow-red = 0.0;
# shadow-green = 0.0;
# shadow-blue = 0.0;
shadow-exclude = [ "name = 'Notification'", "class_g = 'Conky'" ];
shadow-exclude = [ "name = 'Notification'", "class_g = 'Conky'", "class_g ?= 'Notify-osd'" ];
# shadow-exclude = "n:e:Notification";
shadow-ignore-shaped = false;

View File

@ -258,6 +258,14 @@ typedef int (*f_GetVideoSync) (unsigned *);
typedef Bool (*f_GetSyncValuesOML) (Display* dpy, GLXDrawable drawable, int64_t* ust, int64_t* msc, int64_t* sbc);
typedef Bool (*f_WaitForMscOML) (Display* dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t* ust, int64_t* msc, int64_t* sbc);
typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
struct glx_fbconfig {
GLXFBConfig cfg;
bool y_inverted;
};
#endif
typedef struct {
@ -536,7 +544,7 @@ typedef struct {
#endif
#ifdef CONFIG_VSYNC_OPENGL
// === OpenGL VSync related ===
// === OpenGL related ===
/// GLX context.
GLXContext glx_context;
/// Pointer to glXGetVideoSyncSGI function.
@ -547,6 +555,14 @@ typedef struct {
f_GetSyncValuesOML glXGetSyncValuesOML;
/// Pointer to glXWaitForMscOML function.
f_WaitForMscOML glXWaitForMscOML;
/// Pointer to glXBindTexImageEXT function.
f_BindTexImageEXT glXBindTexImageEXT;
/// Pointer to glXReleaseTexImageEXT function.
f_ReleaseTexImageEXT glXReleaseTexImageEXT;
/// FBConfig for RGB GLX pixmap.
struct glx_fbconfig *glx_fbconfig_rgb;
/// FBConfig for RGBA GLX pixmap.
struct glx_fbconfig *glx_fbconfig_rgba;
#endif
// === X extension related ===

View File

@ -3542,6 +3542,16 @@ update_ewmh_active_win(session_t *ps) {
inline static void
ev_property_notify(session_t *ps, XPropertyEvent *ev) {
#ifdef DEBUG_EVENTS
{
// Print out changed atom
char *name = XGetAtomName(ps->dpy, ev->atom);
printf_dbg(" { atom = %s }\n", name);
if (name)
XFree(name);
}
#endif
if (ps->root == ev->window) {
if (ps->o.track_focus && ps->o.use_ewmh_active_win
&& ps->atom_ewmh_active_win == ev->atom) {
@ -3992,40 +4002,11 @@ usage(void) {
* Register a window as symbol, and initialize GLX context if wanted.
*/
static bool
register_cm(session_t *ps, bool glx) {
register_cm(session_t *ps) {
assert(!ps->reg_win);
XVisualInfo *pvi = NULL;
#ifdef CONFIG_VSYNC_OPENGL
// Create a window with the wanted GLX visual
if (glx) {
// Get visual for the window
int attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None };
pvi = glXChooseVisual(ps->dpy, ps->scr, attribs);
if (!pvi) {
printf_errf("(): Failed to choose GLX visual.");
return false;
}
// Create the window
XSetWindowAttributes swa = {
.colormap = XCreateColormap(ps->dpy, ps->root, pvi->visual, AllocNone),
.border_pixel = 0,
};
pvi->screen = ps->scr;
ps->reg_win = XCreateWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0, pvi->depth,
InputOutput, pvi->visual, CWBorderPixel | CWColormap, &swa);
}
// Otherwise, create a simple window
else
#endif
{
ps->reg_win = XCreateSimpleWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0,
ps->reg_win = XCreateSimpleWindow(ps->dpy, ps->root, 0, 0, 1, 1, 0,
None, None);
}
if (!ps->reg_win) {
printf_errf("(): Failed to create window.");
@ -4036,26 +4017,6 @@ register_cm(session_t *ps, bool glx) {
if (ps->redirected)
XCompositeUnredirectWindow(ps->dpy, ps->reg_win, CompositeRedirectManual);
#ifdef CONFIG_VSYNC_OPENGL
if (glx) {
// Get GLX context
ps->glx_context = glXCreateContext(ps->dpy, pvi, None, GL_TRUE);
if (!ps->glx_context) {
printf_errf("(): Failed to get GLX context.");
return false;
}
// Attach GLX context
if (!glXMakeCurrent(ps->dpy, ps->reg_win, ps->glx_context)) {
printf_errf("(): Failed to attach GLX context.");
return false;
}
}
#endif
if (pvi)
XFree(pvi);
Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr",
NULL, 0, NULL, NULL, NULL);
@ -4478,6 +4439,10 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
usage();
}
// Check for abundant positional arguments
if (optind < argc)
printf_errfq(1, "(): compton doesn't accept positional arguments.");
return;
}
@ -4893,6 +4858,155 @@ swopti_handle_timeout(session_t *ps, struct timeval *ptv) {
}
}
#ifdef CONFIG_VSYNC_OPENGL
/**
* Get a GLX FBConfig.
*/
static inline bool
opengl_update_fbconfig(session_t *ps, bool alpha, struct glx_fbconfig **ppcfg) {
const int FBCONFIG_ATTRS[] = {
(alpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT: GLX_BIND_TO_TEXTURE_RGB_EXT), True,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
GLX_DOUBLEBUFFER, True,
GLX_Y_INVERTED_EXT, GLX_DONT_CARE,
None
};
if (*ppcfg) {
free(*ppcfg);
*ppcfg = NULL;
}
int count = 0;
GLXFBConfig *cfgs = glXChooseFBConfig(ps->dpy, ps->scr, FBCONFIG_ATTRS, &count);
if (!count || !cfgs) {
if (cfgs)
XFree(cfgs);
return false;
};
*ppcfg = malloc(sizeof(struct glx_fbconfig));
(*ppcfg)->cfg = cfgs[0];
{
int inverted = 0;
glXGetFBConfigAttrib(ps->dpy, (*ppcfg)->cfg, GLX_Y_INVERTED_EXT, &inverted);
(*ppcfg)->y_inverted = inverted;
}
XFree(cfgs);
return true;
}
/**
* Initialize OpenGL.
*/
static bool
opengl_init(session_t *ps, bool need_render) {
// Check for GLX extension
if (!ps->glx_exists) {
if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error))
ps->glx_exists = true;
else {
printf_errf("(): No GLX extension.");
goto opengl_init_err;
}
}
// Ensure GLX_EXT_texture_from_pixmap exists
if (need_render && !opengl_hasext(ps, "GLX_EXT_texture_from_pixmap")) {
goto opengl_init_err;
}
{
// Get XVisualInfo
XVisualInfo *pvis = NULL;
{
XVisualInfo vreq = { .visualid = XVisualIDFromVisual(ps->vis) };
int nitems = 0;
pvis = XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems);
}
if (!pvis) {
printf_errf("(): Failed to acquire XVisualInfo for current visual.");
goto opengl_init_err;
}
// Ensure the visual is double-buffered
if (need_render) {
int value = 0;
glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value);
if (!value) {
XFree(pvis);
printf_errf("(): Default GLX visual is not double-buffered.");
goto opengl_init_err;
}
}
// Get GLX context
ps->glx_context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE);
XFree(pvis);
}
if (!ps->glx_context) {
printf_errf("(): Failed to get GLX context.");
goto opengl_init_err;
}
// Attach GLX context
if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) {
printf_errf("(): Failed to attach GLX context.");
goto opengl_init_err;
}
// Acquire function addresses
if (need_render) {
ps->glXBindTexImageEXT = (f_BindTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT");
ps->glXReleaseTexImageEXT = (f_ReleaseTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT");
if (!ps->glXBindTexImageEXT || !ps->glXReleaseTexImageEXT) {
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
goto opengl_init_err;
}
}
// Acquire FBConfigs
if (need_render
&& (!(ps->glx_fbconfig_rgb || opengl_update_fbconfig(ps, false, &ps->glx_fbconfig_rgb))
|| !(ps->glx_fbconfig_rgba || opengl_update_fbconfig(ps, true, &ps->glx_fbconfig_rgba)))) {
printf_errf("(): Failed to acquire GLX fbconfig.");
goto opengl_init_err;
}
if (need_render) {
glViewport(0, 0, ps->root_width, ps->root_height);
}
return true;
opengl_init_err:
opengl_destroy(ps);
return false;
}
static void
opengl_destroy(session_t *ps) {
if (ps->glx_context) {
glXDestroyContext(ps->dpy, ps->glx_context);
ps->glx_context = None;
}
free(ps->glx_fbconfig_rgb);
ps->glx_fbconfig_rgb = NULL;
free(ps->glx_fbconfig_rgba);
ps->glx_fbconfig_rgba = NULL;
}
#endif
/**
* Initialize DRM VSync.
*
@ -4962,10 +5076,10 @@ vsync_opengl_init(session_t *ps) {
// Get video sync functions
if (!ps->glXWaitVideoSyncSGI)
ps->glXGetVideoSyncSGI = (f_GetVideoSync)
glXGetProcAddress ((const GLubyte *) "glXGetVideoSyncSGI");
glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI)
ps->glXWaitVideoSyncSGI = (f_WaitVideoSync)
glXGetProcAddress ((const GLubyte *) "glXWaitVideoSyncSGI");
glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI || !ps->glXGetVideoSyncSGI) {
printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function.");
return false;
@ -5168,9 +5282,14 @@ redir_start(session_t *ps) {
XCompositeRedirectSubwindows(ps->dpy, ps->root, CompositeRedirectManual);
// Unredirect reg_win as this may have an effect on VSync:
/*
// Unredirect GL context window as this may have an effect on VSync:
// < http://dri.freedesktop.org/wiki/CompositeSwap >
XCompositeUnredirectWindow(ps->dpy, ps->reg_win, CompositeRedirectManual);
if (ps->o.paint_on_overlay && ps->overlay) {
XCompositeUnredirectWindow(ps->dpy, ps->overlay,
CompositeRedirectManual);
} */
// Must call XSync() here
XSync(ps->dpy, False);
@ -5729,8 +5848,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
exit(1);
// Create registration window
// Must not precede VSync init functions because they may create the window
if (!ps->reg_win && !register_cm(ps, false))
if (!ps->reg_win && !register_cm(ps))
exit(1);
init_atoms(ps);
@ -5961,11 +6079,9 @@ session_destroy(session_t *ps) {
XDestroyWindow(ps->dpy, ps->reg_win);
ps->reg_win = None;
}
#ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context) {
glXDestroyContext(ps->dpy, ps->glx_context);
ps->glx_context = None;
}
opengl_destroy(ps);
#endif
// Free double buffer

View File

@ -9,6 +9,7 @@
#include "common.h"
#include <ctype.h>
#include <math.h>
#include <sys/select.h>
#include <limits.h>
@ -22,7 +23,7 @@
// We references some definitions in drm.h, which could also be found in
// /usr/src/linux/include/drm/drm.h, but that path is probably even less
// reliable than libdrm
#include <libdrm/drm.h>
#include <drm.h>
#include <sys/ioctl.h>
#include <errno.h>
#endif
@ -705,40 +706,7 @@ static void __attribute__ ((noreturn))
usage(void);
static bool
register_cm(session_t *ps, bool glx);
#ifdef CONFIG_VSYNC_OPENGL
/**
* Ensure we have a GLX context.
*/
static inline bool
ensure_glx_context(session_t *ps) {
if (ps->glx_context)
return true;
// Check for GLX extension
if (!ps->glx_exists) {
if (glXQueryExtension(ps->dpy, &ps->glx_event, &ps->glx_error))
ps->glx_exists = true;
else {
printf_errf("(): No GLX extension.");
return false;
}
}
// Create GLX context
if (ps->reg_win) {
XDestroyWindow(ps->dpy, ps->reg_win);
ps->reg_win = None;
}
if (!register_cm(ps, true) || !ps->glx_context) {
printf_errf("(): Failed to acquire GLX context.");
return false;
}
return true;
}
#endif
register_cm(session_t *ps);
inline static void
ev_focus_in(session_t *ps, XFocusChangeEvent *ev);
@ -919,6 +887,44 @@ 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.
*/
static inline bool
ensure_glx_context(session_t *ps) {
// Create GLX context
if (!ps->glx_context)
opengl_init(ps, false);
return ps->glx_context;
}
#endif
static bool
vsync_drm_init(session_t *ps);