diff --git a/.github/issue_template.md b/.github/issue_template.md index b2202212b9..680a80fc2d 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -5,6 +5,8 @@ ### GPU, drivers, and screen setup // Example: NVidia GTX 670, nvidia-drivers 381.09, two monitors configured side-by-side with xrandr +// Please include the version of the video drivers (xf86-video-*) and mesa. +// Please also paste the output of `glxinfo -B` here. ### Environment // Tell us something about the desktop environment you are using, for example: i3-gaps, Gnome Shell, etc. diff --git a/compton.sample.conf b/compton.sample.conf index 024a7aff2d..bc6ad51abd 100644 --- a/compton.sample.conf +++ b/compton.sample.conf @@ -77,6 +77,8 @@ invert-color-include = [ ]; # glx-no-rebind-pixmap = true; glx-swap-method = "undefined"; # glx-use-gpushader4 = true; +# xrender-sync = true; +# xrender-sync-fence = true; # Window type settings wintypes: diff --git a/man/compton.1.asciidoc b/man/compton.1.asciidoc index 5dc2fd7b7f..dd8968149c 100644 --- a/man/compton.1.asciidoc +++ b/man/compton.1.asciidoc @@ -242,7 +242,7 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box + -- * `xrender` backend performs all rendering operations with X Render extension. It is what `xcompmgr` uses, and is generally a safe fallback when you encounter rendering artifacts or instability. -* `glx` (OpenGL) backend performs all rendering operations with OpenGL. It is more friendly to some VSync methods, and has significantly superior performance on color inversion (`--invert-color-include`) or blur (`--blur-background`). It requires proper OpenGL 2.0 support from your driver and hardware. You may wish to look at the GLX performance optimization options below. +* `glx` (OpenGL) backend performs all rendering operations with OpenGL. It is more friendly to some VSync methods, and has significantly superior performance on color inversion (`--invert-color-include`) or blur (`--blur-background`). It requires proper OpenGL 2.0 support from your driver and hardware. You may wish to look at the GLX performance optimization options below. `--xrender-sync` and `--xrender-sync-fence` might be needed on some systems to avoid delay in changes of screen contents. * `xr_glx_hybrid` backend renders the updated screen contents with X Render and presents it on the screen with GLX. It attempts to address the rendering issues some users encountered with GLX backend and enables the better VSync of GLX backends. `--vsync-use-glfinish` might fix some rendering issues with this backend. -- @@ -258,6 +258,12 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box *--glx-use-gpushader4*:: GLX backend: Use 'GL_EXT_gpu_shader4' for some optimization on blur GLSL code. My tests on GTX 670 show no noticeable effect. +*--xrender-sync*:: + Attempt to synchronize client applications' draw calls with `XSync()`, used on GLX backend to ensure up-to-date window content is painted. + +*--xrender-sync-fence*:: + Additionally use X Sync fence to sync clients' draw calls. Needed on nvidia-drivers with GLX backend for some users. May be disabled at compile time with `NO_XSYNC=1`. + *--glx-fshader-win* 'SHADER':: GLX backend: Use specified GLSL fragment shader for rendering window contents. See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` in the source tree for examples. diff --git a/src/c2.c b/src/c2.c index b59e90ae8a..2b91b98ad8 100644 --- a/src/c2.c +++ b/src/c2.c @@ -360,7 +360,7 @@ c2_match_once(session_t *ps, win *w, const c2_ptr_t cond); * Parse a condition string. */ c2_lptr_t * -c2_parsed(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, +c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, void *data) { if (!pattern) return NULL; @@ -1645,9 +1645,9 @@ c2_match_once(session_t *ps, win *w, const c2_ptr_t cond) { * @return true if matched, false otherwise. */ bool -c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, +c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, const c2_lptr_t **cache, void **pdata) { - assert(IsViewable == w->a.map_state); + assert(w->a.map_state == XCB_MAP_STATE_VIEWABLE); // Check if the cached entry matches firstly if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) { diff --git a/src/c2.h b/src/c2.h index 510de411e9..8f50bdf472 100644 --- a/src/c2.h +++ b/src/c2.h @@ -18,17 +18,12 @@ typedef struct session session_t; typedef struct win win; c2_lptr_t * -c2_parsed(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, +c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, void *data); -#define c2_parse(ps, pcondlst, pattern) c2_parsed((ps), (pcondlst), (pattern), NULL) - c2_lptr_t * c2_free_lptr(c2_lptr_t *lp); bool -c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, +c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, const c2_lptr_t **cache, void **pdata); - -#define c2_match(ps, w, condlst, cache) c2_matchd((ps), (w), (condlst), \ - (cache), NULL) diff --git a/src/common.h b/src/common.h index 56ec7ece5f..adf297aab1 100644 --- a/src/common.h +++ b/src/common.h @@ -49,6 +49,10 @@ // #define CONFIG_OPENGL 1 // Whether to enable DBus support with libdbus. // #define CONFIG_DBUS 1 +// Whether to enable X Sync support. +// #define CONFIG_XSYNC 1 +// Whether to enable GLX Sync support. +// #define CONFIG_GLX_XSYNC 1 #ifndef COMPTON_VERSION #define COMPTON_VERSION "unknown" @@ -73,6 +77,7 @@ #include #include +#include #include #include @@ -310,7 +315,7 @@ typedef int (*f_SwapIntervalMESA) (unsigned int interval); typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list); typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer); -#ifdef CONFIG_GLX_SYNC +#ifdef CONFIG_OPENGL // Looks like duplicate typedef of the same type is safe? typedef int64_t GLint64; typedef uint64_t GLuint64; @@ -449,6 +454,11 @@ typedef struct options_t { char *display_repr; /// The backend in use. enum backend backend; + /// Whether to sync X drawing to avoid certain delay issues with + /// GLX backend. + bool xrender_sync; + /// Whether to sync X drawing with X Sync fence. + bool xrender_sync_fence; /// Whether to avoid using stencil buffer under GLX backend. Might be /// unsafe. bool glx_no_stencil; @@ -646,7 +656,6 @@ typedef struct { f_BindTexImageEXT glXBindTexImageProc; /// Pointer to glXReleaseTexImageEXT function. f_ReleaseTexImageEXT glXReleaseTexImageProc; -#ifdef CONFIG_GLX_SYNC /// Pointer to the glFenceSync() function. f_FenceSync glFenceSyncProc; /// Pointer to the glIsSync() function. @@ -659,7 +668,6 @@ typedef struct { f_WaitSync glWaitSyncProc; /// Pointer to the glImportSyncEXT() function. f_ImportSyncEXT glImportSyncEXT; -#endif #ifdef DEBUG_GLX_MARK /// Pointer to StringMarkerGREMEDY function. f_StringMarkerGREMEDY glStringMarkerGREMEDY; @@ -721,6 +729,7 @@ typedef struct session { xcb_render_picture_t tgt_picture; /// Temporary buffer to paint to before sending to display. paint_t tgt_buffer; + XSyncFence tgt_buffer_fence; /// Window ID of the window we register as a symbol. Window reg_win; #ifdef CONFIG_OPENGL @@ -885,6 +894,12 @@ typedef struct session { /// Number of Xinerama screens. int xinerama_nscrs; #endif + /// Whether X Sync extension exists. + bool xsync_exists; + /// Event base number for X Sync extension. + int xsync_event; + /// Error base number for X Sync extension. + int xsync_error; /// Whether X Render convolution filter exists. bool xrfilter_convolution_exists; @@ -1437,7 +1452,7 @@ glx_has_context(session_t *ps) { */ static inline bool win_is_focused_real(session_t *ps, const win *w) { - return IsViewable == w->a.map_state && ps->active_win == w; + return w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->active_win == w; } /** @@ -1463,6 +1478,16 @@ free_all_damage_last(session_t *ps) { pixman_region32_clear(&ps->all_damage_last[i]); } +/** + * Free a XSync fence. + */ +static inline void +free_fence(session_t *ps, XSyncFence *pfence) { + if (*pfence) + XSyncDestroyFence(ps->dpy, *pfence); + *pfence = None; +} + /** * Check if a rectangle includes the whole screen. */ @@ -1613,10 +1638,8 @@ vsync_deinit(session_t *ps); */ ///@{ -#ifdef CONFIG_GLX_SYNC void xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence); -#endif /** * Free a GLX texture. @@ -1701,6 +1724,48 @@ glx_mark_frame(session_t *ps) { ///@} +/** + * Synchronizes a X Render drawable to ensure all pending painting requests + * are completed. + */ +static inline void +xr_sync(session_t *ps, Drawable d, XSyncFence *pfence) { + if (!ps->o.xrender_sync) + return; + + x_sync(ps->c); + if (ps->o.xrender_sync_fence && ps->xsync_exists) { + // TODO: If everybody just follows the rules stated in X Sync prototype, + // we need only one fence per screen, but let's stay a bit cautious right + // now + XSyncFence tmp_fence = None; + if (!pfence) + pfence = &tmp_fence; + assert(pfence); + if (!*pfence) + *pfence = XSyncCreateFence(ps->dpy, d, False); + if (*pfence) { + Bool __attribute__((unused)) triggered = False; + /* if (XSyncQueryFence(ps->dpy, *pfence, &triggered) && triggered) + XSyncResetFence(ps->dpy, *pfence); */ + // The fence may fail to be created (e.g. because of died drawable) + assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || !triggered); + XSyncTriggerFence(ps->dpy, *pfence); + XSyncAwaitFence(ps->dpy, pfence, 1); + assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || triggered); + } + else { + printf_errf("(%#010lx): Failed to create X Sync fence.", d); + } + free_fence(ps, &tmp_fence); + if (*pfence) + XSyncResetFence(ps->dpy, *pfence); + } +#ifdef OPENGL + xr_glx_sync(ps, d, pfence); +#endif +} + /** @name DBus handling */ ///@{ diff --git a/src/compton.c b/src/compton.c index 717194bdb0..13cf52e2a9 100644 --- a/src/compton.c +++ b/src/compton.c @@ -248,6 +248,7 @@ static inline void free_win_res(session_t *ps, win *w) { free_win_res_glx(ps, w); free_paint(ps, &w->paint); + free_fence(ps, &w->fence); pixman_region32_fini(&w->bounding_shape); free_paint(ps, &w->shadow_paint); // BadDamage may be thrown if the window is destroyed @@ -886,6 +887,9 @@ win_build_shadow(session_t *ps, win *w, double opacity) { assert(!w->shadow_paint.pict); w->shadow_paint.pict = shadow_picture_argb; + // Sync it once and only once + xr_sync(ps, w->shadow_paint.pixmap, NULL); + xcb_free_gc(ps->c, gc); xcb_image_destroy(shadow_image); xcb_free_pixmap(ps->c, shadow_pixmap); @@ -986,7 +990,7 @@ long determine_evmask(session_t *ps, Window wid, win_evmode_t mode) { // Check if it's a mapped frame window if (WIN_EVMODE_FRAME == mode - || ((w = find_win(ps, wid)) && IsViewable == w->a.map_state)) { + || ((w = find_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) { evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; if (ps->o.track_focus && !ps->o.use_ewmh_active_win) evmask |= XCB_EVENT_MASK_FOCUS_CHANGE; @@ -994,7 +998,7 @@ long determine_evmask(session_t *ps, Window wid, win_evmode_t mode) { // Check if it's a mapped client window if (WIN_EVMODE_CLIENT == mode - || ((w = find_toplevel(ps, wid)) && IsViewable == w->a.map_state)) { + || ((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) { if (ps->o.frame_opacity || ps->o.track_wdata || ps->track_atom_lst || ps->o.detect_client_opacity) evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; @@ -1215,7 +1219,7 @@ paint_preprocess(session_t *ps, win *list) { const bool was_painted = w->to_paint; const opacity_t opacity_old = w->opacity; // Restore flags from last paint if the window is being faded out - if (IsUnmapped == w->a.map_state) { + if (w->a.map_state == XCB_MAP_STATE_UNMAPPED) { win_set_shadow(ps, w, w->shadow_last); w->fade = w->fade_last; win_set_invert_color(ps, w, w->invert_color_last); @@ -1279,7 +1283,7 @@ paint_preprocess(session_t *ps, win *list) { if (!w->ever_damaged || w->g.x + w->g.width < 1 || w->g.y + w->g.height < 1 || w->g.x >= ps->root_width || w->g.y >= ps->root_height - || ((IsUnmapped == w->a.map_state || w->destroyed) && !w->paint.pixmap) + || ((w->a.map_state == XCB_MAP_STATE_UNMAPPED || w->destroyed) && !w->paint.pixmap) || get_alpha_step(ps, w->opacity) == 0 || w->paint_excluded) to_paint = false; @@ -1627,6 +1631,8 @@ paint_one(session_t *ps, win *w, const region_t *reg_paint) { w->paint.pixmap = xcb_generate_id(ps->c); set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->id, w->paint.pixmap)); + if (w->paint.pixmap) + free_fence(ps, &w->fence); } Drawable draw = w->paint.pixmap; @@ -1643,6 +1649,9 @@ paint_one(session_t *ps, win *w, const region_t *reg_paint) { draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); } + if (IsViewable == w->a.map_state) + xr_sync(ps, draw, &w->fence); + // GLX: Build texture // Let glx_bind_pixmap() determine pixmap size, because if the user // is resizing windows, the width and height we get may not be up-to-date, @@ -1862,7 +1871,7 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co } if (BKEND_XRENDER == ps->o.backend) { - x_set_picture_clip_region(ps, ps->tgt_buffer.pict, 0, 0, region_real); + x_set_picture_clip_region(ps, ps->tgt_picture, 0, 0, region_real); } region_t reg_tmp, *reg_paint; @@ -2023,9 +2032,12 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co glFlush(); glXWaitX(); assert(ps->tgt_buffer.pixmap); + xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence); paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, ps->depth, !ps->o.glx_no_rebind_pixmap); + // See #163 + xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence); if (ps->o.vsync_use_glfinish) glFinish(); else @@ -2082,7 +2094,7 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co static void repair_win(session_t *ps, win *w) { - if (IsViewable != w->a.map_state) + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; region_t parts; @@ -2149,12 +2161,12 @@ map_win(session_t *ps, Window id) { // Don't care about window mapping if it's an InputOnly window // Try avoiding mapping a window twice if (!w || InputOnly == w->a._class - || IsViewable == w->a.map_state) + || w->a.map_state == XCB_MAP_STATE_VIEWABLE) return; assert(!win_is_focused_real(ps, w)); - w->a.map_state = IsViewable; + w->a.map_state = XCB_MAP_STATE_VIEWABLE; cxinerama_win_upd_scr(ps, w); @@ -2255,14 +2267,19 @@ finish_unmap_win(session_t *ps, win **_w) { static void unmap_win(session_t *ps, win **_w) { win *w = *_w; - if (!w || IsUnmapped == w->a.map_state) return; + if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) return; if (w->destroyed) return; + // One last synchronization + if (w->paint.pixmap) + xr_sync(ps, w->paint.pixmap, &w->fence); + free_fence(ps, &w->fence); + // Set focus out win_set_focused(ps, w, false); - w->a.map_state = IsUnmapped; + w->a.map_state = XCB_MAP_STATE_UNMAPPED; // Fading out w->flags |= WFLAG_OPCT_CHANGE; @@ -2669,7 +2686,7 @@ opts_init_track_focus(session_t *ps) { if (!ps->o.use_ewmh_active_win) { // Start listening to FocusChange events for (win *w = ps->list; w; w = w->next) - if (IsViewable == w->a.map_state) + if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) xcb_change_window_attributes(ps->c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]) { determine_evmask(ps, w->id, WIN_EVMODE_FRAME) }); } @@ -2723,6 +2740,14 @@ ev_name(session_t *ps, xcb_generic_event_t *ev) { if (ps->shape_exists && ev->response_type == ps->shape_event) return "ShapeNotify"; + if (ps->xsync_exists) { + int o = ev->response_type - ps->xsync_event; + switch (o) { + CASESTRRET(XSyncCounterNotify); + CASESTRRET(XSyncAlarmNotify); + } + } + sprintf(buf, "Event %d", ev->response_type); return buf; @@ -3114,7 +3139,7 @@ ev_damage_notify(session_t *ps, xcb_damage_notify_event_t *de) { inline static void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) { win *w = find_win(ps, ev->affected_window); - if (!w || IsUnmapped == w->a.map_state) return; + if (!w || w->a.map_state == XCB_MAP_STATE_UNMAPPED) return; /* * Empty bounding_shape may indicated an @@ -3570,7 +3595,6 @@ usage(int ret) { "--backend backend\n" " Choose backend. Possible choices are xrender, glx, and\n" " xr_glx_hybrid" WARNING ".\n" -#undef WARNING "\n" "--glx-no-stencil\n" " GLX backend: Avoid using stencil buffer. Might cause issues\n" @@ -3595,6 +3619,16 @@ usage(int ret) { " GLX backend: Use GL_EXT_gpu_shader4 for some optimization on blur\n" " GLSL code. My tests on GTX 670 show no noticeable effect.\n" "\n" + "--xrender-sync\n" + " Attempt to synchronize client applications' draw calls with XSync(),\n" + " used on GLX backend to ensure up-to-date window content is painted.\n" +#undef WARNING +#define WARNING + "\n" + "--xrender-sync-fence\n" + " Additionally use X Sync fence to sync clients' draw calls. Needed\n" + " on nvidia-drivers with GLX backend for some users." WARNING "\n" + "\n" "--glx-fshader-win shader\n" " GLX backend: Use specified GLSL fragment shader for rendering window\n" " contents.\n" @@ -3612,7 +3646,6 @@ usage(int ret) { "--dbus\n" " Enable remote control via D-Bus. See the D-BUS API section in the\n" " man page for more details." WARNING "\n" -#undef WARNING "\n" "--benchmark cycles\n" " Benchmark mode. Repeatedly paint until reaching the specified cycles.\n" @@ -3626,6 +3659,7 @@ usage(int ret) { ; FILE *f = (ret ? stderr: stdout); fputs(usage_text, f); +#undef WARNING #undef WARNING_DISABLED exit(ret); @@ -4154,12 +4188,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { ps->o.write_pid_path = mstrcpy(optarg); break; P_CASEBOOL(311, vsync_use_glfinish); - case 312: - printf_errf("(): --xrender-sync %s", deprecation_message); - break; - case 313: - printf_errf("(): --xrender-sync-fence %s", deprecation_message); - break; + P_CASEBOOL(312, xrender_sync); + P_CASEBOOL(313, xrender_sync_fence); P_CASEBOOL(315, no_fading_destroyed_argb); P_CASEBOOL(316, force_win_blend); case 317: @@ -4216,6 +4246,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { if (ps->o.blur_background_frame) ps->o.blur_background = true; + if (ps->o.xrender_sync_fence) + ps->o.xrender_sync = true; + // Other variables determined by options // Determine whether we need to track focus changes @@ -4789,8 +4822,10 @@ redir_stop(session_t *ps) { // Destroy all Pictures as they expire once windows are unredirected // If we don't destroy them here, looks like the resources are just // kept inaccessible somehow - for (win *w = ps->list; w; w = w->next) + for (win *w = ps->list; w; w = w->next) { free_paint(ps, &w->paint); + free_fence(ps, &w->fence); + } xcb_composite_unredirect_subwindows(ps->c, ps->root, XCB_COMPOSITE_REDIRECT_MANUAL); // Unmap overlay window @@ -5301,6 +5336,20 @@ session_init(session_t *ps_old, int argc, char **argv) { ps->present_exists = true; } + // Query X Sync + if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) { + // TODO: Fencing may require version >= 3.0? + int major_version_return = 0, minor_version_return = 0; + if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return)) + ps->xsync_exists = true; + } + + if (!ps->xsync_exists && ps->o.xrender_sync_fence) { + printf_errf("(): X Sync extension not found. No X Sync fence sync is " + "possible."); + exit(1); + } + // Query X RandR if ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop) { if (!ps->randr_exists) { @@ -5543,7 +5592,7 @@ session_destroy(session_t *ps) { // Must be put here to avoid segfault next = w->next; - if (IsViewable == w->a.map_state && !w->destroyed) + if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && !w->destroyed) win_ev_stop(ps, w); free_win_res(ps, w); @@ -5614,6 +5663,7 @@ session_destroy(session_t *ps) { ps->tgt_picture = None; else free_picture(ps, &ps->tgt_picture); + free_fence(ps, &ps->tgt_buffer_fence); free_picture(ps, &ps->root_picture); free_paint(ps, &ps->tgt_buffer); diff --git a/src/config.c b/src/config.c index b73512cae9..c5d2c5a63f 100644 --- a/src/config.c +++ b/src/config.c @@ -318,7 +318,7 @@ bool parse_rule_opacity(session_t *ps, const char *src) { // Parse pattern // I hope 1-100 is acceptable for (void *) - return c2_parsed(ps, &ps->o.opacity_rules, endptr, (void *) val); + return c2_parse(ps, &ps->o.opacity_rules, endptr, (void *) val); } /** @@ -329,7 +329,7 @@ condlst_add(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) { if (!pattern) return false; - if (!c2_parse(ps, pcondlst, pattern)) + if (!c2_parse(ps, pcondlst, pattern, NULL)) exit(1); return true; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index e50bea2428..5d58e1bea0 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -353,6 +353,10 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) { exit(1); // --glx-use-gpushader4 lcfg_lookup_bool(&cfg, "glx-use-gpushader4", &ps->o.glx_use_gpushader4); + // --xrender-sync + lcfg_lookup_bool(&cfg, "xrender-sync", &ps->o.xrender_sync); + // --xrender-sync-fence + lcfg_lookup_bool(&cfg, "xrender-sync-fence", &ps->o.xrender_sync_fence); if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval)) printf_errf("(): \"clear-shadow\" is removed as an option, and is always" @@ -367,10 +371,6 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) { printf_errf("(): \"glx-use-copysubbuffermesa\" %s", deprecation_message); if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval) printf_errf("(): \"glx-copy-from-front\" %s", deprecation_message); - if (lcfg_lookup_bool(&cfg, "xrender-sync", &bval) && bval) - printf_errf("(): \"xrender-sync\" %s", deprecation_message); - if (lcfg_lookup_bool(&cfg, "xrender-sync-fence", &bval) && bval) - printf_errf("(): \"xrender-sync-fence\" %s", deprecation_message); // Wintype settings diff --git a/src/meson.build b/src/meson.build index e1749e0793..f6596fe50b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,10 +4,10 @@ deps = [ dependency('xcb', version: '>=1.9.2') ] -cflags = [ ] - srcs = ['compton.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'diagnostic.c'] +cflags = [] + required_package = [ 'x11', 'x11-xcb', 'xcb-renderutil', 'xcb-render', 'xcb-damage', 'xcb-randr', diff --git a/src/opengl.c b/src/opengl.c index 6258b06274..dd10b8a42a 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -185,6 +185,23 @@ get_visualinfo_from_visual(session_t *ps, xcb_visualid_t visual) { return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems); } +void +xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) { + if (*pfence) { + // GLsync sync = ps->psglx->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + GLsync sync = ps->psglx->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0); + /* GLenum ret = ps->psglx->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT, + 1000); + assert(GL_CONDITION_SATISFIED == ret); */ + XSyncTriggerFence(ps->dpy, *pfence); + XFlush(ps->dpy); + ps->psglx->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED); + // ps->psglx->glDeleteSyncProc(sync); + // XSyncResetFence(ps->dpy, *pfence); + } + glx_check_err(ps); +} + #ifdef DEBUG_GLX_DEBUG_CONTEXT static inline GLXFBConfig get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) { @@ -362,7 +379,6 @@ glx_init(session_t *ps, bool need_render) { goto glx_init_end; } -#ifdef CONFIG_GLX_SYNC psglx->glFenceSyncProc = (f_FenceSync) glXGetProcAddress((const GLubyte *) "glFenceSync"); psglx->glIsSyncProc = (f_IsSync) @@ -381,7 +397,6 @@ glx_init(session_t *ps, bool need_render) { printf_errf("(): Failed to acquire GLX sync functions."); goto glx_init_end; } -#endif } // Acquire FBConfigs diff --git a/src/win.c b/src/win.c index 341eccc546..075ad84523 100644 --- a/src/win.c +++ b/src/win.c @@ -2,7 +2,6 @@ // Copyright (c) 2011-2013, Christopher Jeffrey // Copyright (c) 2013 Richard Grenville -#include #include #include #include @@ -318,7 +317,7 @@ void win_determine_mode(session_t *ps, win *w) { void win_calc_opacity(session_t *ps, win *w) { opacity_t opacity = OPAQUE; - if (w->destroyed || IsViewable != w->a.map_state) + if (w->destroyed || w->a.map_state != XCB_MAP_STATE_VIEWABLE) opacity = 0; else { // Try obeying opacity property and window type opacity firstly @@ -350,7 +349,7 @@ void win_calc_dim(session_t *ps, win *w) { bool dim; // Make sure we do nothing if the window is unmapped / destroyed - if (w->destroyed || IsViewable != w->a.map_state) + if (w->destroyed || w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; if (ps->o.inactive_dim && !(w->focused)) { @@ -381,8 +380,8 @@ void win_determine_fade(session_t *ps, win *w) { } // Ignore other possible causes of fading state changes after window // gets unmapped - else if (IsViewable != w->a.map_state) { - } else if (c2_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst)) + else if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) { + } else if (c2_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst, NULL)) w->fade = false; else w->fade = ps->o.wintype_fade[w->window_type]; @@ -454,9 +453,9 @@ void win_determine_shadow(session_t *ps, win *w) { if (UNSET != w->shadow_force) shadow_new = w->shadow_force; - else if (IsViewable == w->a.map_state) + else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) shadow_new = (ps->o.wintype_shadow[w->window_type] && - !c2_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst) && + !c2_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst, NULL) && !(ps->o.shadow_ignore_shaped && w->bounding_shaped && !w->rounded_corners) && !(ps->o.respect_prop_shadow && 0 == w->prop_shadow)); @@ -481,9 +480,9 @@ void win_determine_invert_color(session_t *ps, win *w) { if (UNSET != w->invert_color_force) invert_color_new = w->invert_color_force; - else if (IsViewable == w->a.map_state) + else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) invert_color_new = - c2_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst); + c2_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst, NULL); win_set_invert_color(ps, w, invert_color_new); } @@ -504,12 +503,12 @@ void win_set_blur_background(session_t *ps, win *w, bool blur_background_new) { * Determine if a window should have background blurred. */ void win_determine_blur_background(session_t *ps, win *w) { - if (IsViewable != w->a.map_state) + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; bool blur_background_new = ps->o.blur_background && - !c2_match(ps, w, ps->o.blur_background_blacklist, &w->cache_bbblst); + !c2_match(ps, w, ps->o.blur_background_blacklist, &w->cache_bbblst, NULL); win_set_blur_background(ps, w, blur_background_new); } @@ -518,13 +517,13 @@ void win_determine_blur_background(session_t *ps, win *w) { * Update window opacity according to opacity rules. */ void win_update_opacity_rule(session_t *ps, win *w) { - if (IsViewable != w->a.map_state) + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; opacity_t opacity = OPAQUE; bool is_set = false; void *val = NULL; - if (c2_matchd(ps, w, ps->o.opacity_rules, &w->cache_oparule, &val)) { + if (c2_match(ps, w, ps->o.opacity_rules, &w->cache_oparule, &val)) { opacity = ((double)(long)val) / 100.0 * OPAQUE; is_set = true; } @@ -569,12 +568,12 @@ void win_on_factor_change(session_t *ps, win *w) { win_determine_blur_background(ps, w); if (ps->o.opacity_rules) win_update_opacity_rule(ps, w); - if (IsViewable == w->a.map_state && ps->o.paint_blacklist) + if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.paint_blacklist) w->paint_excluded = - c2_match(ps, w, ps->o.paint_blacklist, &w->cache_pblst); - if (IsViewable == w->a.map_state && ps->o.unredir_if_possible_blacklist) + c2_match(ps, w, ps->o.paint_blacklist, &w->cache_pblst, NULL); + if (w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->o.unredir_if_possible_blacklist) w->unredir_if_possible_excluded = c2_match( - ps, w, ps->o.unredir_if_possible_blacklist, &w->cache_uipblst); + ps, w, ps->o.unredir_if_possible_blacklist, &w->cache_uipblst, NULL); w->reg_ignore_valid = false; } @@ -636,7 +635,7 @@ void win_mark_client(session_t *ps, win *w, Window client) { // If the window isn't mapped yet, stop here, as the function will be // called in map_win() - if (IsViewable != w->a.map_state) + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) return; xcb_change_window_attributes(ps->c, client, XCB_CW_EVENT_MASK, @@ -844,9 +843,9 @@ bool add_win(session_t *ps, Window id, Window prev) { xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(ps->c, id); xcb_get_window_attributes_reply_t *a = xcb_get_window_attributes_reply(ps->c, acookie, NULL); xcb_get_geometry_reply_t *g = xcb_get_geometry_reply(ps->c, gcookie, NULL); - if (!a || IsUnviewable == a->map_state) { + if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) { // Failed to get window attributes probably means the window is gone - // already. IsUnviewable means the window is already reparented + // already. Unviewable means the window is already reparented // elsewhere. free(a); free(g); @@ -867,8 +866,8 @@ bool add_win(session_t *ps, Window id, Window prev) { // Delay window mapping int map_state = new->a.map_state; - assert(IsViewable == map_state || IsUnmapped == map_state); - new->a.map_state = IsUnmapped; + assert(map_state == XCB_MAP_STATE_VIEWABLE || map_state == XCB_MAP_STATE_UNMAPPED); + new->a.map_state = XCB_MAP_STATE_UNMAPPED; if (InputOutput == new->a._class) { // Create Damage for window @@ -896,7 +895,7 @@ bool add_win(session_t *ps, Window id, Window prev) { } #endif - if (IsViewable == map_state) { + if (map_state == XCB_MAP_STATE_VIEWABLE) { map_win(ps, id); } @@ -917,9 +916,10 @@ void win_update_focused(session_t *ps, win *w) { // windows specially if (ps->o.wintype_focus[w->window_type] || (ps->o.mark_wmwin_focused && w->wmwin) - || (ps->o.mark_ovredir_focused - && w->id == w->client_win && !w->wmwin) - || (IsViewable == w->a.map_state && c2_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst))) + || (ps->o.mark_ovredir_focused && + w->id == w->client_win && !w->wmwin) + || (w->a.map_state == XCB_MAP_STATE_VIEWABLE && + c2_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst, NULL))) w->focused = true; // If window grouping detection is enabled, mark the window active if @@ -1109,7 +1109,7 @@ win_on_focus_change(session_t *ps, win *w) { void win_set_focused(session_t *ps, win *w, bool focused) { // Unmapped windows will have their focused state reset on map - if (IsUnmapped == w->a.map_state) + if (w->a.map_state == XCB_MAP_STATE_UNMAPPED) return; if (win_is_focused_real(ps, w) == focused) return; diff --git a/src/win.h b/src/win.h index 4f0e6748cf..e0cedbe041 100644 --- a/src/win.h +++ b/src/win.h @@ -4,6 +4,7 @@ #pragma once #include #include +#include #include // FIXME shouldn't need this @@ -101,6 +102,8 @@ struct win { winmode_t mode; /// Whether the window has been damaged at least once. bool ever_damaged; + /// X Sync fence of drawable. + XSyncFence fence; /// Whether the window was damaged after last paint. bool pixmap_damaged; /// Damage of the window. diff --git a/src/x.c b/src/x.c index 25dfeddcd1..02939d8404 100644 --- a/src/x.c +++ b/src/x.c @@ -317,6 +317,15 @@ x_print_error(unsigned long serial, uint8_t major, uint8_t minor, uint8_t error_ } #endif + if (ps->xsync_exists) { + o = error_code - ps->xsync_error; + switch (o) { + CASESTRRET2(XSyncBadCounter); + CASESTRRET2(XSyncBadAlarm); + CASESTRRET2(XSyncBadFence); + } + } + switch (error_code) { CASESTRRET2(BadAccess); CASESTRRET2(BadAlloc); diff --git a/src/x.h b/src/x.h index b89acbd799..77d5dd02cc 100644 --- a/src/x.h +++ b/src/x.h @@ -3,7 +3,6 @@ #pragma once #include #include -#include #include #include #include