Skip to content

Commit b18d46b

Browse files
committed
Revert "Remove xrender-sync and xrender-sync-fence"
This reverts commit 50e2259. Temporarily revert the removal until we have more information about this whole thing. Turns out a couple of drivers don't work properly without the sync fence, including intel, llvmpipe and NVIDIA. Although sync fence is needed, from the information I have gathered (looking at old bug reports, protocol specifications, look at other compositors' code), compton's usage of it is not proper. So we need to rewrite it in the future, after we get more information from driver developers. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
1 parent ab7a2f1 commit b18d46b

9 files changed

+174
-23
lines changed

compton.sample.conf

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ invert-color-include = [ ];
7777
# glx-no-rebind-pixmap = true;
7878
glx-swap-method = "undefined";
7979
# glx-use-gpushader4 = true;
80+
# xrender-sync = true;
81+
# xrender-sync-fence = true;
8082

8183
# Window type settings
8284
wintypes:

man/compton.1.asciidoc

+7-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box
242242
+
243243
--
244244
* `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.
245-
* `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.
245+
* `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.
246246
* `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.
247247
--
248248

@@ -258,6 +258,12 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box
258258
*--glx-use-gpushader4*::
259259
GLX backend: Use 'GL_EXT_gpu_shader4' for some optimization on blur GLSL code. My tests on GTX 670 show no noticeable effect.
260260

261+
*--xrender-sync*::
262+
Attempt to synchronize client applications' draw calls with `XSync()`, used on GLX backend to ensure up-to-date window content is painted.
263+
264+
*--xrender-sync-fence*::
265+
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`.
266+
261267
*--glx-fshader-win* 'SHADER'::
262268
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.
263269

src/common.h

+70-5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
// #define CONFIG_OPENGL 1
5050
// Whether to enable DBus support with libdbus.
5151
// #define CONFIG_DBUS 1
52+
// Whether to enable X Sync support.
53+
// #define CONFIG_XSYNC 1
54+
// Whether to enable GLX Sync support.
55+
// #define CONFIG_GLX_XSYNC 1
5256

5357
#ifndef COMPTON_VERSION
5458
#define COMPTON_VERSION "unknown"
@@ -73,6 +77,7 @@
7377

7478
#include <X11/Xlib-xcb.h>
7579
#include <X11/Xlib.h>
80+
#include <X11/extensions/sync.h>
7681

7782
#include <xcb/composite.h>
7883
#include <xcb/render.h>
@@ -310,7 +315,7 @@ typedef int (*f_SwapIntervalMESA) (unsigned int interval);
310315
typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
311316
typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
312317

313-
#ifdef CONFIG_GLX_SYNC
318+
#ifdef CONFIG_OPENGL
314319
// Looks like duplicate typedef of the same type is safe?
315320
typedef int64_t GLint64;
316321
typedef uint64_t GLuint64;
@@ -449,6 +454,11 @@ typedef struct options_t {
449454
char *display_repr;
450455
/// The backend in use.
451456
enum backend backend;
457+
/// Whether to sync X drawing to avoid certain delay issues with
458+
/// GLX backend.
459+
bool xrender_sync;
460+
/// Whether to sync X drawing with X Sync fence.
461+
bool xrender_sync_fence;
452462
/// Whether to avoid using stencil buffer under GLX backend. Might be
453463
/// unsafe.
454464
bool glx_no_stencil;
@@ -646,7 +656,6 @@ typedef struct {
646656
f_BindTexImageEXT glXBindTexImageProc;
647657
/// Pointer to glXReleaseTexImageEXT function.
648658
f_ReleaseTexImageEXT glXReleaseTexImageProc;
649-
#ifdef CONFIG_GLX_SYNC
650659
/// Pointer to the glFenceSync() function.
651660
f_FenceSync glFenceSyncProc;
652661
/// Pointer to the glIsSync() function.
@@ -659,7 +668,6 @@ typedef struct {
659668
f_WaitSync glWaitSyncProc;
660669
/// Pointer to the glImportSyncEXT() function.
661670
f_ImportSyncEXT glImportSyncEXT;
662-
#endif
663671
#ifdef DEBUG_GLX_MARK
664672
/// Pointer to StringMarkerGREMEDY function.
665673
f_StringMarkerGREMEDY glStringMarkerGREMEDY;
@@ -721,6 +729,7 @@ typedef struct session {
721729
xcb_render_picture_t tgt_picture;
722730
/// Temporary buffer to paint to before sending to display.
723731
paint_t tgt_buffer;
732+
XSyncFence tgt_buffer_fence;
724733
/// Window ID of the window we register as a symbol.
725734
Window reg_win;
726735
#ifdef CONFIG_OPENGL
@@ -885,6 +894,12 @@ typedef struct session {
885894
/// Number of Xinerama screens.
886895
int xinerama_nscrs;
887896
#endif
897+
/// Whether X Sync extension exists.
898+
bool xsync_exists;
899+
/// Event base number for X Sync extension.
900+
int xsync_event;
901+
/// Error base number for X Sync extension.
902+
int xsync_error;
888903
/// Whether X Render convolution filter exists.
889904
bool xrfilter_convolution_exists;
890905

@@ -1463,6 +1478,16 @@ free_all_damage_last(session_t *ps) {
14631478
pixman_region32_clear(&ps->all_damage_last[i]);
14641479
}
14651480

1481+
/**
1482+
* Free a XSync fence.
1483+
*/
1484+
static inline void
1485+
free_fence(session_t *ps, XSyncFence *pfence) {
1486+
if (*pfence)
1487+
XSyncDestroyFence(ps->dpy, *pfence);
1488+
*pfence = None;
1489+
}
1490+
14661491
/**
14671492
* Check if a rectangle includes the whole screen.
14681493
*/
@@ -1613,10 +1638,8 @@ vsync_deinit(session_t *ps);
16131638
*/
16141639
///@{
16151640

1616-
#ifdef CONFIG_GLX_SYNC
16171641
void
16181642
xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence);
1619-
#endif
16201643

16211644
/**
16221645
* Free a GLX texture.
@@ -1701,6 +1724,48 @@ glx_mark_frame(session_t *ps) {
17011724

17021725
///@}
17031726

1727+
/**
1728+
* Synchronizes a X Render drawable to ensure all pending painting requests
1729+
* are completed.
1730+
*/
1731+
static inline void
1732+
xr_sync(session_t *ps, Drawable d, XSyncFence *pfence) {
1733+
if (!ps->o.xrender_sync)
1734+
return;
1735+
1736+
x_sync(ps->c);
1737+
if (ps->o.xrender_sync_fence && ps->xsync_exists) {
1738+
// TODO: If everybody just follows the rules stated in X Sync prototype,
1739+
// we need only one fence per screen, but let's stay a bit cautious right
1740+
// now
1741+
XSyncFence tmp_fence = None;
1742+
if (!pfence)
1743+
pfence = &tmp_fence;
1744+
assert(pfence);
1745+
if (!*pfence)
1746+
*pfence = XSyncCreateFence(ps->dpy, d, False);
1747+
if (*pfence) {
1748+
Bool __attribute__((unused)) triggered = False;
1749+
/* if (XSyncQueryFence(ps->dpy, *pfence, &triggered) && triggered)
1750+
XSyncResetFence(ps->dpy, *pfence); */
1751+
// The fence may fail to be created (e.g. because of died drawable)
1752+
assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || !triggered);
1753+
XSyncTriggerFence(ps->dpy, *pfence);
1754+
XSyncAwaitFence(ps->dpy, pfence, 1);
1755+
assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || triggered);
1756+
}
1757+
else {
1758+
printf_errf("(%#010lx): Failed to create X Sync fence.", d);
1759+
}
1760+
free_fence(ps, &tmp_fence);
1761+
if (*pfence)
1762+
XSyncResetFence(ps->dpy, *pfence);
1763+
}
1764+
#ifdef OPENGL
1765+
xr_glx_sync(ps, d, pfence);
1766+
#endif
1767+
}
1768+
17041769
/** @name DBus handling
17051770
*/
17061771
///@{

src/compton.c

+59-9
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ static inline void
248248
free_win_res(session_t *ps, win *w) {
249249
free_win_res_glx(ps, w);
250250
free_paint(ps, &w->paint);
251+
free_fence(ps, &w->fence);
251252
pixman_region32_fini(&w->bounding_shape);
252253
free_paint(ps, &w->shadow_paint);
253254
// BadDamage may be thrown if the window is destroyed
@@ -886,6 +887,9 @@ win_build_shadow(session_t *ps, win *w, double opacity) {
886887
assert(!w->shadow_paint.pict);
887888
w->shadow_paint.pict = shadow_picture_argb;
888889

890+
// Sync it once and only once
891+
xr_sync(ps, w->shadow_paint.pixmap, NULL);
892+
889893
xcb_free_gc(ps->c, gc);
890894
xcb_image_destroy(shadow_image);
891895
xcb_free_pixmap(ps->c, shadow_pixmap);
@@ -1627,6 +1631,8 @@ paint_one(session_t *ps, win *w, const region_t *reg_paint) {
16271631
w->paint.pixmap = xcb_generate_id(ps->c);
16281632
set_ignore_cookie(ps,
16291633
xcb_composite_name_window_pixmap(ps->c, w->id, w->paint.pixmap));
1634+
if (w->paint.pixmap)
1635+
free_fence(ps, &w->fence);
16301636
}
16311637

16321638
Drawable draw = w->paint.pixmap;
@@ -1643,6 +1649,9 @@ paint_one(session_t *ps, win *w, const region_t *reg_paint) {
16431649
draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
16441650
}
16451651

1652+
if (IsViewable == w->a.map_state)
1653+
xr_sync(ps, draw, &w->fence);
1654+
16461655
// GLX: Build texture
16471656
// Let glx_bind_pixmap() determine pixmap size, because if the user
16481657
// is resizing windows, the width and height we get may not be up-to-date,
@@ -2023,9 +2032,12 @@ paint_all(session_t *ps, region_t *region, const region_t *region_real, win * co
20232032
glFlush();
20242033
glXWaitX();
20252034
assert(ps->tgt_buffer.pixmap);
2035+
xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence);
20262036
paint_bind_tex(ps, &ps->tgt_buffer,
20272037
ps->root_width, ps->root_height, ps->depth,
20282038
!ps->o.glx_no_rebind_pixmap);
2039+
// See #163
2040+
xr_sync(ps, ps->tgt_buffer.pixmap, &ps->tgt_buffer_fence);
20292041
if (ps->o.vsync_use_glfinish)
20302042
glFinish();
20312043
else
@@ -2259,6 +2271,11 @@ unmap_win(session_t *ps, win **_w) {
22592271

22602272
if (w->destroyed) return;
22612273

2274+
// One last synchronization
2275+
if (w->paint.pixmap)
2276+
xr_sync(ps, w->paint.pixmap, &w->fence);
2277+
free_fence(ps, &w->fence);
2278+
22622279
// Set focus out
22632280
win_set_focused(ps, w, false);
22642281

@@ -2723,6 +2740,14 @@ ev_name(session_t *ps, xcb_generic_event_t *ev) {
27232740
if (ps->shape_exists && ev->response_type == ps->shape_event)
27242741
return "ShapeNotify";
27252742

2743+
if (ps->xsync_exists) {
2744+
int o = ev->response_type - ps->xsync_event;
2745+
switch (o) {
2746+
CASESTRRET(XSyncCounterNotify);
2747+
CASESTRRET(XSyncAlarmNotify);
2748+
}
2749+
}
2750+
27262751
sprintf(buf, "Event %d", ev->response_type);
27272752

27282753
return buf;
@@ -3570,7 +3595,6 @@ usage(int ret) {
35703595
"--backend backend\n"
35713596
" Choose backend. Possible choices are xrender, glx, and\n"
35723597
" xr_glx_hybrid" WARNING ".\n"
3573-
#undef WARNING
35743598
"\n"
35753599
"--glx-no-stencil\n"
35763600
" GLX backend: Avoid using stencil buffer. Might cause issues\n"
@@ -3595,6 +3619,16 @@ usage(int ret) {
35953619
" GLX backend: Use GL_EXT_gpu_shader4 for some optimization on blur\n"
35963620
" GLSL code. My tests on GTX 670 show no noticeable effect.\n"
35973621
"\n"
3622+
"--xrender-sync\n"
3623+
" Attempt to synchronize client applications' draw calls with XSync(),\n"
3624+
" used on GLX backend to ensure up-to-date window content is painted.\n"
3625+
#undef WARNING
3626+
#define WARNING
3627+
"\n"
3628+
"--xrender-sync-fence\n"
3629+
" Additionally use X Sync fence to sync clients' draw calls. Needed\n"
3630+
" on nvidia-drivers with GLX backend for some users." WARNING "\n"
3631+
"\n"
35983632
"--glx-fshader-win shader\n"
35993633
" GLX backend: Use specified GLSL fragment shader for rendering window\n"
36003634
" contents.\n"
@@ -3612,7 +3646,6 @@ usage(int ret) {
36123646
"--dbus\n"
36133647
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
36143648
" man page for more details." WARNING "\n"
3615-
#undef WARNING
36163649
"\n"
36173650
"--benchmark cycles\n"
36183651
" Benchmark mode. Repeatedly paint until reaching the specified cycles.\n"
@@ -3626,6 +3659,7 @@ usage(int ret) {
36263659
;
36273660
FILE *f = (ret ? stderr: stdout);
36283661
fputs(usage_text, f);
3662+
#undef WARNING
36293663
#undef WARNING_DISABLED
36303664

36313665
exit(ret);
@@ -4154,12 +4188,8 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
41544188
ps->o.write_pid_path = mstrcpy(optarg);
41554189
break;
41564190
P_CASEBOOL(311, vsync_use_glfinish);
4157-
case 312:
4158-
printf_errf("(): --xrender-sync %s", deprecation_message);
4159-
break;
4160-
case 313:
4161-
printf_errf("(): --xrender-sync-fence %s", deprecation_message);
4162-
break;
4191+
P_CASEBOOL(312, xrender_sync);
4192+
P_CASEBOOL(313, xrender_sync_fence);
41634193
P_CASEBOOL(315, no_fading_destroyed_argb);
41644194
P_CASEBOOL(316, force_win_blend);
41654195
case 317:
@@ -4216,6 +4246,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
42164246
if (ps->o.blur_background_frame)
42174247
ps->o.blur_background = true;
42184248

4249+
if (ps->o.xrender_sync_fence)
4250+
ps->o.xrender_sync = true;
4251+
42194252
// Other variables determined by options
42204253

42214254
// Determine whether we need to track focus changes
@@ -4789,8 +4822,10 @@ redir_stop(session_t *ps) {
47894822
// Destroy all Pictures as they expire once windows are unredirected
47904823
// If we don't destroy them here, looks like the resources are just
47914824
// kept inaccessible somehow
4792-
for (win *w = ps->list; w; w = w->next)
4825+
for (win *w = ps->list; w; w = w->next) {
47934826
free_paint(ps, &w->paint);
4827+
free_fence(ps, &w->fence);
4828+
}
47944829

47954830
xcb_composite_unredirect_subwindows(ps->c, ps->root, XCB_COMPOSITE_REDIRECT_MANUAL);
47964831
// Unmap overlay window
@@ -5301,6 +5336,20 @@ session_init(session_t *ps_old, int argc, char **argv) {
53015336
ps->present_exists = true;
53025337
}
53035338

5339+
// Query X Sync
5340+
if (XSyncQueryExtension(ps->dpy, &ps->xsync_event, &ps->xsync_error)) {
5341+
// TODO: Fencing may require version >= 3.0?
5342+
int major_version_return = 0, minor_version_return = 0;
5343+
if (XSyncInitialize(ps->dpy, &major_version_return, &minor_version_return))
5344+
ps->xsync_exists = true;
5345+
}
5346+
5347+
if (!ps->xsync_exists && ps->o.xrender_sync_fence) {
5348+
printf_errf("(): X Sync extension not found. No X Sync fence sync is "
5349+
"possible.");
5350+
exit(1);
5351+
}
5352+
53045353
// Query X RandR
53055354
if ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop) {
53065355
if (!ps->randr_exists) {
@@ -5614,6 +5663,7 @@ session_destroy(session_t *ps) {
56145663
ps->tgt_picture = None;
56155664
else
56165665
free_picture(ps, &ps->tgt_picture);
5666+
free_fence(ps, &ps->tgt_buffer_fence);
56175667

56185668
free_picture(ps, &ps->root_picture);
56195669
free_paint(ps, &ps->tgt_buffer);

src/config_libconfig.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
353353
exit(1);
354354
// --glx-use-gpushader4
355355
lcfg_lookup_bool(&cfg, "glx-use-gpushader4", &ps->o.glx_use_gpushader4);
356+
// --xrender-sync
357+
lcfg_lookup_bool(&cfg, "xrender-sync", &ps->o.xrender_sync);
358+
// --xrender-sync-fence
359+
lcfg_lookup_bool(&cfg, "xrender-sync-fence", &ps->o.xrender_sync_fence);
356360

357361
if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval))
358362
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) {
367371
printf_errf("(): \"glx-use-copysubbuffermesa\" %s", deprecation_message);
368372
if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval)
369373
printf_errf("(): \"glx-copy-from-front\" %s", deprecation_message);
370-
if (lcfg_lookup_bool(&cfg, "xrender-sync", &bval) && bval)
371-
printf_errf("(): \"xrender-sync\" %s", deprecation_message);
372-
if (lcfg_lookup_bool(&cfg, "xrender-sync-fence", &bval) && bval)
373-
printf_errf("(): \"xrender-sync-fence\" %s", deprecation_message);
374374

375375
// Wintype settings
376376

0 commit comments

Comments
 (0)