From 85e7d188037757f1e790afd34380f4bffdf5d92d Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Sun, 21 Apr 2013 22:30:22 +0800 Subject: [PATCH] Improvement: --glx-swap-method & --fade-exclude - GLX backend: Add --glx-swap-method, to reduce painting region if the driver uses exchange or copy buffer swaps. Untested. - Add --fade-exclude, to disable fading on specific windows based on some conditions. Untested. - Expose GLX backend options through configuration file. Add fetching of GLX backend options through D-Bus. - Use NULL pointer instead of element count to delimit string arrays in parse_vsync()/parse_backend()/parse_glx_swap_method(). - Add documentation about "wintypes" section in configuration file. --- compton.sample.conf | 8 +++++++ man/compton.1.asciidoc | 18 +++++++++++++-- src/common.h | 36 +++++++++++++++++++++++++---- src/compton.c | 52 +++++++++++++++++++++++++++++++++++++++--- src/dbus.c | 12 ++++++++++ src/opengl.c | 14 +++++++++++- 6 files changed, 130 insertions(+), 10 deletions(-) diff --git a/compton.sample.conf b/compton.sample.conf index ba208aa..2b7ba9d 100644 --- a/compton.sample.conf +++ b/compton.sample.conf @@ -34,6 +34,7 @@ fading = true; fade-in-step = 0.03; fade-out-step = 0.03; # no-fading-openclose = true; +fade-exclude = [ ]; # Other backend = "xrender" @@ -53,6 +54,13 @@ detect-transient = true; detect-client-leader = true; invert-color-include = [ ]; +# GLX backend +# glx-no-stencil = true; +glx-copy-from-front = false; +# glx-use-copysubbuffermesa = true; +# glx-no-rebind-pixmap = true; +glx-swap-method = "undefined"; + # Window type settings wintypes: { diff --git a/man/compton.1.asciidoc b/man/compton.1.asciidoc index fc64cc1..158d49f 100644 --- a/man/compton.1.asciidoc +++ b/man/compton.1.asciidoc @@ -2,7 +2,7 @@ compton(1) ========== :doctype: manpage :man source: compton -:man version: nightly-20121105 +:man version: nightly-20130421 :man manual: LOCAL USER COMMANDS NAME @@ -154,6 +154,9 @@ OPTIONS *--shadow-exclude* 'CONDITION':: Specify a list of conditions of windows that should have no shadow. +*--fade-exclude* 'CONDITION':: + Specify a list of conditions of windows that should not be faded. + *--focus-exclude* 'CONDITION':: Specify a list of conditions of windows that should always be considered focused. @@ -279,7 +282,18 @@ This is the old condition format we once used. Support of this format might be r CONFIGURATION FILES ------------------- -compton could read from a configuration file if libconfig support is compiled in. If *--config* is not used, compton will seek for a configuration file in `$XDG_CONFIG_HOME/compton.conf` (`~/.config/compton.conf`, usually), then `~/.compton.conf`, then `compton.conf` under `$XDG_DATA_DIRS` (often `/etc/xdg/compton.conf`). Most commandline switches could be replaced with an option in configuration file, and some options are exposed only in configuration files (presently, some window-type-specific settings). compton uses general libconfig configurtion file format. A sample configuration file is available as `compton.sample.conf` in the source tree. +compton could read from a configuration file if libconfig support is compiled in. If *--config* is not used, compton will seek for a configuration file in `$XDG_CONFIG_HOME/compton.conf` (`~/.config/compton.conf`, usually), then `~/.compton.conf`, then `compton.conf` under `$XDG_DATA_DIRS` (often `/etc/xdg/compton.conf`). + +compton uses general libconfig configurtion file format. A sample configuration file is available as `compton.sample.conf` in the source tree. Most commandline switches each could be replaced with an option in configuration file, thus documented above. Window-type-specific settings are exposed only in configuration file and has the following format: + +------------ +wintypes: +{ + WINDOW_TYPE = { fade = BOOL; shadow = BOOL; opacity = FLOAT; focus = BOOL; }; +}; +------------ + +'WINDOW_TYPE' is one of the 15 window types defined in EWMH standard: "unknown", "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal", "dropdown_menu", "popup_menu", "tooltip", "notify", "combo", and "dnd". "fade" and "shadow" controls window-type-specific shadow and fade settings. "opacity" controls default opacity of the window type. "focus" controls whether the window of this type is to be always considered focused. (By default, all window types except "normal" and "dialog" has this on.) SIGNALS ------- diff --git a/src/common.h b/src/common.h index d5abdfd..3058b4d 100644 --- a/src/common.h +++ b/src/common.h @@ -284,6 +284,14 @@ enum backend { NUM_BKEND, }; +/// @brief Possible swap methods. +enum glx_swap_method { + SWAPM_UNDEFINED, + SWAPM_EXCHANGE, + SWAPM_COPY, + NUM_SWAPM, +}; + typedef struct _glx_texture glx_texture_t; #ifdef CONFIG_VSYNC_OPENGL @@ -374,6 +382,8 @@ typedef struct { bool glx_use_copysubbuffermesa; /// Whether to avoid rebinding pixmap on window damage. bool glx_no_rebind_pixmap; + /// GLX swap method we assume OpenGL uses. + enum glx_swap_method glx_swap_method; /// Whether to try to detect WM windows and mark them as focused. bool mark_wmwin_focused; /// Whether to mark override-redirect windows as focused. @@ -563,6 +573,8 @@ typedef struct { struct timeval time_start; /// The region needs to painted on next paint. XserverRegion all_damage; + /// The region damaged on the last paint. + XserverRegion all_damage_last; /// Whether all windows are currently redirected. bool redirected; /// Whether there's a highest full-screen window, and all windows could @@ -942,8 +954,9 @@ typedef enum { } win_evmode_t; extern const char * const WINTYPES[NUM_WINTYPES]; -extern const char * const VSYNC_STRS[NUM_VSYNC]; -extern const char * const BACKEND_STRS[NUM_BKEND]; +extern const char * const VSYNC_STRS[NUM_VSYNC + 1]; +extern const char * const BACKEND_STRS[NUM_BKEND + 1]; +extern const char * const GLX_SWAP_METHODS_STRS[NUM_SWAPM + 1]; extern session_t *ps_g; // == Debugging code == @@ -1313,11 +1326,12 @@ normalize_d(double d) { */ static inline bool parse_vsync(session_t *ps, const char *str) { - for (vsync_t i = 0; i < (sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0])); ++i) + for (vsync_t i = 0; VSYNC_STRS[i]; ++i) if (!strcasecmp(str, VSYNC_STRS[i])) { ps->o.vsync = i; return true; } + printf_errf("(\"%s\"): Invalid vsync argument.", str); return false; } @@ -1327,7 +1341,7 @@ parse_vsync(session_t *ps, const char *str) { */ static inline bool parse_backend(session_t *ps, const char *str) { - for (enum backend i = 0; i < (sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0])); ++i) + for (enum backend i = 0; BACKEND_STRS[i]; ++i) if (!strcasecmp(str, BACKEND_STRS[i])) { ps->o.backend = i; return true; @@ -1336,6 +1350,20 @@ parse_backend(session_t *ps, const char *str) { return false; } +/** + * Parse a glx_swap_method option argument. + */ +static inline bool +parse_glx_swap_method(session_t *ps, const char *str) { + for (enum glx_swap_method i = 0; GLX_SWAP_METHODS_STRS[i]; ++i) + if (!strcasecmp(str, GLX_SWAP_METHODS_STRS[i])) { + ps->o.glx_swap_method = i; + return true; + } + printf_errf("(\"%s\"): Invalid GLX swap method argument.", str); + return false; +} + timeout_t * timeout_insert(session_t *ps, time_ms_t interval, bool (*callback)(session_t *ps, timeout_t *ptmout), void *data); diff --git a/src/compton.c b/src/compton.c index ae4130f..eb94d9b 100644 --- a/src/compton.c +++ b/src/compton.c @@ -32,19 +32,29 @@ const char * const WINTYPES[NUM_WINTYPES] = { }; /// Names of VSync modes. -const char * const VSYNC_STRS[NUM_VSYNC] = { +const char * const VSYNC_STRS[NUM_VSYNC + 1] = { "none", // VSYNC_NONE "drm", // VSYNC_DRM "opengl", // VSYNC_OPENGL "opengl-oml", // VSYNC_OPENGL_OML "opengl-swc", // VSYNC_OPENGL_SWC "opengl-mswc", // VSYNC_OPENGL_MSWC + NULL }; /// Names of backends. -const char * const BACKEND_STRS[NUM_BKEND] = { +const char * const BACKEND_STRS[NUM_BKEND + 1] = { "xrender", // BKEND_XRENDER "glx", // BKEND_GLX + NULL +}; + +/// Names of GLX swap methods. +const char * const GLX_SWAP_METHODS_STRS[NUM_SWAPM + 1] = { + "undefined", // SWAPM_UNDEFINED + "exchange", // SWAPM_EXCHANGE + "copy", // SWAPM_COPY + NULL }; /// Function pointers to init VSync modes. @@ -2205,7 +2215,8 @@ calc_dim(session_t *ps, win *w) { */ static void win_determine_fade(session_t *ps, win *w) { - if (ps->o.no_fading_openclose && w->in_openclose) + if ((ps->o.no_fading_openclose && w->in_openclose) + || win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst)) w->fade = false; else w->fade = ps->o.wintype_fade[w->window_type]; @@ -4129,6 +4140,8 @@ usage(void) { " Try to detect WM windows and mark them as active.\n" "--shadow-exclude condition\n" " Exclude conditions for shadows.\n" + "--fade-exclude condition\n" + " Exclude conditions for fading.\n" "--mark-ovredir-focused\n" " Mark windows that have no WM frame as active.\n" "--no-fading-openclose\n" @@ -4246,6 +4259,12 @@ usage(void) { " GLX backend: Avoid rebinding pixmap on window damage. Probably\n" " could improve performance on rapid window content changes, but is\n" " known to break things on some drivers.\n" + "--glx-swap-method undefined/exchange/copy\n" + " GLX backend: GLX buffer swap method we assume. Could be\n" + " \"undefined\", \"exchange\", or \"copy\". \"undefined\" is the slowest\n" + " and the safest; \"exchange\" and \"copy\" are faster but may fail on\n" + " some drivers. Useless with --glx-use-copysubbuffermesa. Defaults to\n" + " \"undefined\".\n" #undef WARNING #ifndef CONFIG_DBUS #define WARNING WARNING_DISABLED @@ -4631,6 +4650,8 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) { &ps->o.detect_client_leader); // --shadow-exclude parse_cfg_condlst(ps, &cfg, &ps->o.shadow_blacklist, "shadow-exclude"); + // --fade-exclude + parse_cfg_condlst(ps, &cfg, &ps->o.fade_blacklist, "fade-exclude"); // --focus-exclude parse_cfg_condlst(ps, &cfg, &ps->o.focus_blacklist, "focus-exclude"); // --invert-color-include @@ -4645,6 +4666,18 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) { // --blur-background-fixed lcfg_lookup_bool(&cfg, "blur-background-fixed", &ps->o.blur_background_fixed); + // --glx-no-stencil + lcfg_lookup_bool(&cfg, "glx-no-stencil", &ps->o.glx_no_stencil); + // --glx-copy-from-front + lcfg_lookup_bool(&cfg, "glx-copy-from-front", &ps->o.glx_copy_from_front); + // --glx-use-copysubbuffermesa + lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &ps->o.glx_use_copysubbuffermesa); + // --glx-no-rebind-pixmap + lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &ps->o.glx_no_rebind_pixmap); + // --glx-swap-method + if (config_lookup_string(&cfg, "glx-swap-method", &sval) + && !parse_glx_swap_method(ps, sval)) + exit(1); // Wintype settings { wintype_t i; @@ -4721,6 +4754,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { { "blur-background-exclude", required_argument, NULL, 296 }, { "active-opacity", required_argument, NULL, 297 }, { "glx-no-rebind-pixmap", no_argument, NULL, 298 }, + { "glx-swap-method", required_argument, NULL, 299 }, + { "fade-exclude", required_argument, NULL, 300 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -4935,6 +4970,15 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { ps->o.active_opacity = (normalize_d(atof(optarg)) * OPAQUE); break; P_CASEBOOL(298, glx_no_rebind_pixmap); + case 299: + // --glx-swap-method + if (!parse_glx_swap_method(ps, optarg)) + exit(1); + break; + case 300: + // --fade-exclude + condlst_add(ps, &ps->o.fade_blacklist, optarg); + break; default: usage(); break; @@ -5842,6 +5886,7 @@ session_init(session_t *ps_old, int argc, char **argv) { .tmout_lst = NULL, .all_damage = None, + .all_damage_last = None, .time_start = { 0, 0 }, .redirected = false, .unredir_possible = false, @@ -6285,6 +6330,7 @@ session_destroy(session_t *ps) { free_root_tile(ps); free_region(ps, &ps->screen_reg); free_region(ps, &ps->all_damage); + free_region(ps, &ps->all_damage_last); free(ps->expose_rects); free(ps->shadow_corner); free(ps->shadow_top); diff --git a/src/dbus.c b/src/dbus.c index 5a1a3e3..bef51a7 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -909,6 +909,18 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) { cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool); cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool); +#ifdef CONFIG_VSYNC_OPENGL + cdbus_m_opts_get_do(glx_no_stencil, cdbus_reply_bool); + cdbus_m_opts_get_do(glx_copy_from_front, cdbus_reply_bool); + cdbus_m_opts_get_do(glx_use_copysubbuffermesa, cdbus_reply_bool); + cdbus_m_opts_get_do(glx_no_rebind_pixmap, cdbus_reply_bool); + if (!strcmp("glx_swap_method", target)) { + assert(ps->o.glx_swap_method < sizeof(GLX_SWAP_METHODS_STRS) / sizeof(GLX_SWAP_METHODS_STRS[0])); + cdbus_reply_string(ps, msg, GLX_SWAP_METHODS_STRS[ps->o.glx_swap_method]); + return true; + } +#endif + cdbus_m_opts_get_do(track_focus, cdbus_reply_bool); cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool); cdbus_m_opts_get_do(track_leader, cdbus_reply_bool); diff --git a/src/opengl.c b/src/opengl.c index 6560afe..2ea8a8c 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -545,10 +545,20 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) { ps->glx_z = 0.0; // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Exchange swap is interested in the raw damaged region only + XserverRegion all_damage_last = ps->all_damage_last; + ps->all_damage_last = None; + if (SWAPM_EXCHANGE == ps->o.glx_swap_method && *preg) + ps->all_damage_last = copy_region(ps, *preg); + // OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer, // we could redraw the whole screen or copy unmodified pixels from // front buffer with --glx-copy-from-front. - if (ps->o.glx_use_copysubbuffermesa || !*preg) { + if (ps->o.glx_use_copysubbuffermesa || SWAPM_COPY == ps->o.glx_swap_method + || !*preg) { + } + else if (SWAPM_EXCHANGE == ps->o.glx_swap_method && all_damage_last) { + XFixesUnionRegion(ps->dpy, *preg, *preg, all_damage_last); } else if (!ps->o.glx_copy_from_front) { free_region(ps, preg); @@ -572,6 +582,8 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) { } } + free_region(ps, &all_damage_last); + glx_set_clip(ps, *preg, NULL); }