Improvement #7: Add double buffering
Add double buffering with X DBE extension in hope to get rid of the tearing issue. Thanks to cairo-compmgr for providing hints. Could be enabled with --dbe. Only very limited tests have been done, I don't know if it actually solves the tearing issue. My estimation is it is harmful for performance, but I found no clear evidence. Experimental, so no configuration file option is available for it. MONITOR_REPAINT is broken if --dbe is turned on, this is intended for testing whether DBE is actually working.
This commit is contained in:
parent
fe2146f1a5
commit
5dd544d29d
|
@ -39,8 +39,14 @@ Display *dpy = NULL;
|
||||||
int scr;
|
int scr;
|
||||||
|
|
||||||
Window root;
|
Window root;
|
||||||
Picture root_picture;
|
/// Picture of root window. Destination of painting in no-DBE painting
|
||||||
Picture root_buffer;
|
/// mode.
|
||||||
|
Picture root_picture = None;
|
||||||
|
/// Temporary buffer to paint to before sending to display.
|
||||||
|
Picture root_buffer = None;
|
||||||
|
/// DBE back buffer for root window. Used in DBE painting mode.
|
||||||
|
XdbeBackBuffer root_dbe = None;
|
||||||
|
|
||||||
Picture black_picture;
|
Picture black_picture;
|
||||||
Picture cshadow_picture;
|
Picture cshadow_picture;
|
||||||
/// Picture used for dimming inactive windows.
|
/// Picture used for dimming inactive windows.
|
||||||
|
@ -109,6 +115,8 @@ Bool glx_exists = False;
|
||||||
int glx_event, glx_error;
|
int glx_event, glx_error;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Bool dbe_exists = False;
|
||||||
|
|
||||||
/* shadows */
|
/* shadows */
|
||||||
conv *gaussian_map;
|
conv *gaussian_map;
|
||||||
|
|
||||||
|
@ -163,6 +171,7 @@ static options_t opts = {
|
||||||
|
|
||||||
.refresh_rate = 0,
|
.refresh_rate = 0,
|
||||||
.vsync = VSYNC_NONE,
|
.vsync = VSYNC_NONE,
|
||||||
|
.dbe = False,
|
||||||
|
|
||||||
.wintype_shadow = { False },
|
.wintype_shadow = { False },
|
||||||
.shadow_red = 0.0,
|
.shadow_red = 0.0,
|
||||||
|
@ -1557,18 +1566,29 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MONITOR_REPAINT
|
#ifdef MONITOR_REPAINT
|
||||||
|
// Note: MONITOR_REPAINT cannot work with DBE right now.
|
||||||
root_buffer = root_picture;
|
root_buffer = root_picture;
|
||||||
#else
|
#else
|
||||||
if (!root_buffer) {
|
if (!root_buffer) {
|
||||||
Pixmap root_pixmap = XCreatePixmap(
|
// DBE painting mode: Directly paint to a Picture of the back buffer
|
||||||
dpy, root, root_width, root_height,
|
if (opts.dbe) {
|
||||||
DefaultDepth(dpy, scr));
|
root_buffer = XRenderCreatePicture(dpy, root_dbe,
|
||||||
|
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
// No-DBE painting mode: Paint to an intermediate Picture then paint
|
||||||
|
// the Picture to root window
|
||||||
|
else {
|
||||||
|
Pixmap root_pixmap = XCreatePixmap(
|
||||||
|
dpy, root, root_width, root_height,
|
||||||
|
DefaultDepth(dpy, scr));
|
||||||
|
|
||||||
root_buffer = XRenderCreatePicture(dpy, root_pixmap,
|
root_buffer = XRenderCreatePicture(dpy, root_pixmap,
|
||||||
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)),
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
XFreePixmap(dpy, root_pixmap);
|
XFreePixmap(dpy, root_pixmap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1674,7 +1694,16 @@ paint_all(Display *dpy, XserverRegion region, win *t) {
|
||||||
XFixesDestroyRegion(dpy, reg_tmp);
|
XFixesDestroyRegion(dpy, reg_tmp);
|
||||||
XFixesDestroyRegion(dpy, reg_tmp2);
|
XFixesDestroyRegion(dpy, reg_tmp2);
|
||||||
|
|
||||||
if (root_buffer != root_picture) {
|
// DBE painting mode, only need to swap the buffer
|
||||||
|
if (opts.dbe) {
|
||||||
|
XdbeSwapInfo swap_info = {
|
||||||
|
.swap_window = root,
|
||||||
|
// Is it safe to use XdbeUndefined?
|
||||||
|
.swap_action = XdbeCopied
|
||||||
|
};
|
||||||
|
XdbeSwapBuffers(dpy, &swap_info, 1);
|
||||||
|
}
|
||||||
|
else if (root_buffer != root_picture) {
|
||||||
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, None);
|
XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, None);
|
||||||
XRenderComposite(
|
XRenderComposite(
|
||||||
dpy, PictOpSrc, root_buffer, None,
|
dpy, PictOpSrc, root_buffer, None,
|
||||||
|
@ -3240,6 +3269,9 @@ usage(void) {
|
||||||
"--alpha-step val\n"
|
"--alpha-step val\n"
|
||||||
" Step for pregenerating alpha pictures. 0.01 - 1.0. Defaults to\n"
|
" Step for pregenerating alpha pictures. 0.01 - 1.0. Defaults to\n"
|
||||||
" 0.03.\n"
|
" 0.03.\n"
|
||||||
|
"--dbe\n"
|
||||||
|
" Enable DBE painting mode, intended to use with VSync to\n"
|
||||||
|
" (hopefully) eliminate tearing.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Format of a condition:\n"
|
"Format of a condition:\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -3624,6 +3656,7 @@ get_cfg(int argc, char *const *argv) {
|
||||||
{ "refresh-rate", required_argument, NULL, 269 },
|
{ "refresh-rate", required_argument, NULL, 269 },
|
||||||
{ "vsync", required_argument, NULL, 270 },
|
{ "vsync", required_argument, NULL, 270 },
|
||||||
{ "alpha-step", required_argument, NULL, 271 },
|
{ "alpha-step", required_argument, NULL, 271 },
|
||||||
|
{ "dbe", no_argument, NULL, 272 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -3810,6 +3843,10 @@ get_cfg(int argc, char *const *argv) {
|
||||||
// --alpha-step
|
// --alpha-step
|
||||||
opts.alpha_step = atof(optarg);
|
opts.alpha_step = atof(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 272:
|
||||||
|
// --dbe
|
||||||
|
opts.dbe = True;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
@ -4190,6 +4227,19 @@ init_alpha_picts(Display *dpy) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize double buffer.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_dbe(void) {
|
||||||
|
if (!(root_dbe = XdbeAllocateBackBufferName(dpy, root, XdbeCopied))) {
|
||||||
|
fprintf(stderr, "Failed to create double buffer. Double buffering "
|
||||||
|
"turned off.\n");
|
||||||
|
opts.dbe = False;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv) {
|
main(int argc, char **argv) {
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
@ -4279,6 +4329,22 @@ main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Query X DBE extension
|
||||||
|
if (opts.dbe) {
|
||||||
|
int dbe_ver_major = 0, dbe_ver_minor = 0;
|
||||||
|
if (XdbeQueryExtension(dpy, &dbe_ver_major, &dbe_ver_minor))
|
||||||
|
if (dbe_ver_major >= 1)
|
||||||
|
dbe_exists = True;
|
||||||
|
else
|
||||||
|
fprintf(stderr, "DBE extension version too low. Double buffering "
|
||||||
|
"impossible.\n");
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "No DBE extension. Double buffering impossible.\n");
|
||||||
|
}
|
||||||
|
if (!dbe_exists)
|
||||||
|
opts.dbe = False;
|
||||||
|
}
|
||||||
|
|
||||||
register_cm((VSYNC_OPENGL == opts.vsync));
|
register_cm((VSYNC_OPENGL == opts.vsync));
|
||||||
|
|
||||||
// Initialize software/DRM/OpenGL VSync
|
// Initialize software/DRM/OpenGL VSync
|
||||||
|
@ -4287,6 +4353,9 @@ main(int argc, char **argv) {
|
||||||
|| (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init()))
|
|| (VSYNC_OPENGL == opts.vsync && !vsync_opengl_init()))
|
||||||
opts.vsync = VSYNC_NONE;
|
opts.vsync = VSYNC_NONE;
|
||||||
|
|
||||||
|
if (opts.dbe)
|
||||||
|
init_dbe();
|
||||||
|
|
||||||
if (opts.fork_after_register) fork_after();
|
if (opts.fork_after_register) fork_after();
|
||||||
|
|
||||||
get_atoms();
|
get_atoms();
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
#include <X11/extensions/Xrender.h>
|
#include <X11/extensions/Xrender.h>
|
||||||
#include <X11/extensions/shape.h>
|
#include <X11/extensions/shape.h>
|
||||||
#include <X11/extensions/Xrandr.h>
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#include <X11/extensions/Xdbe.h>
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_DRM
|
#ifdef CONFIG_VSYNC_DRM
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -314,6 +315,8 @@ typedef struct _options {
|
||||||
int refresh_rate;
|
int refresh_rate;
|
||||||
/// VSync method to use;
|
/// VSync method to use;
|
||||||
vsync_t vsync;
|
vsync_t vsync;
|
||||||
|
/// Whether to enable double buffer.
|
||||||
|
Bool dbe;
|
||||||
|
|
||||||
// Shadow
|
// Shadow
|
||||||
Bool wintype_shadow[NUM_WINTYPES];
|
Bool wintype_shadow[NUM_WINTYPES];
|
||||||
|
|
Loading…
Reference in New Issue