Improvement: --glx-use-copysubbuffermesa
- GLX backend: Add --glx-use-copysubbuffermesa, to use MESA_copy_sub_buffer to do partial screen update. Huge performance boost on mesa drivers for partial screen updates, but does not work for nvidia-drivers and may break VSync. Automagically overrides --glx-copy-from-front. - Add rect_is_fullscreen() to reuse code. Misc changes.
This commit is contained in:
parent
8208ec6dc8
commit
4b734c1fa1
|
@ -11,6 +11,7 @@ partially doing this out of a desire to learn Xlib.
|
||||||
|
|
||||||
## Changes from xcompmgr:
|
## Changes from xcompmgr:
|
||||||
|
|
||||||
|
* OpenGL backend (`--backend glx`), in addition to the old X Render backend.
|
||||||
* __inactive window transparency / dimming__
|
* __inactive window transparency / dimming__
|
||||||
* __titlebar/frame transparency__ (specified with `-e`)
|
* __titlebar/frame transparency__ (specified with `-e`)
|
||||||
* menu transparency (thanks to Dana)
|
* menu transparency (thanks to Dana)
|
||||||
|
|
|
@ -127,6 +127,7 @@ OPTIONS
|
||||||
* 'drm': VSync with 'DRM_IOCTL_WAIT_VBLANK'. May only work on some drivers. Experimental.
|
* 'drm': VSync with 'DRM_IOCTL_WAIT_VBLANK'. May only work on some drivers. Experimental.
|
||||||
* 'opengl': Try to VSync with 'SGI_swap_control' OpenGL extension. Only work on some drivers. Experimental.
|
* 'opengl': Try to VSync with 'SGI_swap_control' OpenGL extension. Only work on some drivers. Experimental.
|
||||||
* 'opengl-oml': Try to VSync with 'OML_sync_control' OpenGL extension. Only work on some drivers. Experimental.
|
* 'opengl-oml': Try to VSync with 'OML_sync_control' OpenGL extension. Only work on some drivers. Experimental.
|
||||||
|
* 'opengl-swc': Try to VSync with 'SGI_swap_control' OpenGL extension. Only work on some drivers. Works only with GLX backend. Known to be most effective on many drivers. Does not actually control paint timing, only buffer swap is affected, so it doesn't have the effect of *--sw-opti* unlike other methods. Experimental.
|
||||||
|
|
||||||
(Note some VSync methods may not be enabled at compile time.)
|
(Note some VSync methods may not be enabled at compile time.)
|
||||||
--
|
--
|
||||||
|
@ -176,6 +177,18 @@ OPTIONS
|
||||||
*--invert-color-include* condition::
|
*--invert-color-include* condition::
|
||||||
Specify a list of conditions of windows that should be painted with inverted color. Resource-hogging, and is not well tested.
|
Specify a list of conditions of windows that should be painted with inverted color. Resource-hogging, and is not well tested.
|
||||||
|
|
||||||
|
*--backend* backend::
|
||||||
|
Specify the backend to use: 'xrender` or 'glx'. GLX (OpenGL) backend generally has much superior performance as far as you have a graphic card/chip and driver.
|
||||||
|
|
||||||
|
*--glx-no-stencil*::
|
||||||
|
GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer. Might cause incorrect opacity when rendering transparent content and cannot work with *--blur-background*. May have a positive or negative effect on performance. (My test shows a 10% slowdown.)
|
||||||
|
|
||||||
|
*--glx-copy-from-front*::
|
||||||
|
GLX backend: Copy unmodified regions from front buffer instead of redrawing them all. My tests with nvidia-drivers show a 10% decrease in performance when the whole screen is modified, but a 20% increase when only 1/4 is. My tests on nouveau show terrible slowdown.
|
||||||
|
|
||||||
|
*--glx-use-copysubbuffermesa*::
|
||||||
|
GLX backend: Use MESA_copy_sub_buffer to do partial screen update. My tests on nouveau shows a 200% performance boost when only 1/4 of the screen is updated. May break VSync and is not available on some drivers. Overrides *--glx-copy-from-front*.
|
||||||
|
|
||||||
*--dbus*::
|
*--dbus*::
|
||||||
Enable remote control via D-Bus. See the *D-BUS API* section below for more details.
|
Enable remote control via D-Bus. See the *D-BUS API* section below for more details.
|
||||||
|
|
||||||
|
@ -312,10 +325,10 @@ $ compton -c --shadow-red 1 --shadow-green 1 --shadow-blue 1
|
||||||
$ compton -c --shadow-exclude 'class_g = "wbar"'
|
$ compton -c --shadow-exclude 'class_g = "wbar"'
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* Enable OpenGL vsync:
|
* Enable OpenGL SGI_swap_control VSync with GLX backend:
|
||||||
+
|
+
|
||||||
------------
|
------------
|
||||||
$ compton --vsync opengl
|
$ compton --backend glx --vsync opengl-swc
|
||||||
------------
|
------------
|
||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
|
|
18
src/common.h
18
src/common.h
|
@ -284,6 +284,8 @@ typedef int (*f_SwapIntervalSGI) (int interval);
|
||||||
typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
|
typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
|
||||||
typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
|
typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
|
||||||
|
|
||||||
|
typedef void (*f_CopySubBuffer) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
|
||||||
|
|
||||||
/// @brief Wrapper of a GLX FBConfig.
|
/// @brief Wrapper of a GLX FBConfig.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GLXFBConfig cfg;
|
GLXFBConfig cfg;
|
||||||
|
@ -344,6 +346,8 @@ typedef struct {
|
||||||
bool glx_no_stencil;
|
bool glx_no_stencil;
|
||||||
/// Whether to copy unmodified regions from front buffer.
|
/// Whether to copy unmodified regions from front buffer.
|
||||||
bool glx_copy_from_front;
|
bool glx_copy_from_front;
|
||||||
|
/// Whether to use glXCopySubBufferMESA() to update screen.
|
||||||
|
bool glx_use_copysubbuffermesa;
|
||||||
/// Whether to try to detect WM windows and mark them as focused.
|
/// Whether to try to detect WM windows and mark them as focused.
|
||||||
bool mark_wmwin_focused;
|
bool mark_wmwin_focused;
|
||||||
/// Whether to mark override-redirect windows as focused.
|
/// Whether to mark override-redirect windows as focused.
|
||||||
|
@ -624,6 +628,8 @@ typedef struct {
|
||||||
f_BindTexImageEXT glXBindTexImageProc;
|
f_BindTexImageEXT glXBindTexImageProc;
|
||||||
/// Pointer to glXReleaseTexImageEXT function.
|
/// Pointer to glXReleaseTexImageEXT function.
|
||||||
f_ReleaseTexImageEXT glXReleaseTexImageProc;
|
f_ReleaseTexImageEXT glXReleaseTexImageProc;
|
||||||
|
/// Pointer to glXCopySubBufferMESA function.
|
||||||
|
f_CopySubBuffer glXCopySubBufferProc;
|
||||||
/// FBConfig-s for GLX pixmap of different depths.
|
/// FBConfig-s for GLX pixmap of different depths.
|
||||||
glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1];
|
glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1];
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
@ -1490,6 +1496,15 @@ free_region(session_t *ps, XserverRegion *p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a rectangle includes the whole screen.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
rect_is_fullscreen(session_t *ps, int x, int y, unsigned wid, unsigned hei) {
|
||||||
|
return (x <= 0 && y <= 0
|
||||||
|
&& (x + wid) >= ps->root_width && (y + hei) >= ps->root_height);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a window has a specific property.
|
* Determine if a window has a specific property.
|
||||||
*
|
*
|
||||||
|
@ -1621,6 +1636,9 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
int x, int y, int dx, int dy, int width, int height, int z,
|
int x, int y, int dx, int dy, int width, int height, int z,
|
||||||
double opacity, bool neg, XserverRegion reg_tgt);
|
double opacity, bool neg, XserverRegion reg_tgt);
|
||||||
|
|
||||||
|
void
|
||||||
|
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
GLuint
|
GLuint
|
||||||
glx_create_shader(GLenum shader_type, const char *shader_str);
|
glx_create_shader(GLenum shader_type, const char *shader_str);
|
||||||
|
|
|
@ -1736,7 +1736,6 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free up all temporary regions
|
// Free up all temporary regions
|
||||||
XFixesDestroyRegion(ps->dpy, region);
|
|
||||||
XFixesDestroyRegion(ps->dpy, reg_tmp);
|
XFixesDestroyRegion(ps->dpy, reg_tmp);
|
||||||
XFixesDestroyRegion(ps->dpy, reg_tmp2);
|
XFixesDestroyRegion(ps->dpy, reg_tmp2);
|
||||||
|
|
||||||
|
@ -1783,7 +1782,10 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
case BKEND_GLX:
|
case BKEND_GLX:
|
||||||
glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
if (ps->o.glx_use_copysubbuffermesa)
|
||||||
|
glx_swap_copysubbuffermesa(ps, region);
|
||||||
|
else
|
||||||
|
glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -1802,6 +1804,8 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
XFixesDestroyRegion(ps->dpy, region);
|
||||||
|
|
||||||
#ifdef DEBUG_REPAINT
|
#ifdef DEBUG_REPAINT
|
||||||
print_timestamp(ps);
|
print_timestamp(ps);
|
||||||
struct timespec now = get_time_timespec();
|
struct timespec now = get_time_timespec();
|
||||||
|
@ -4151,9 +4155,14 @@ usage(void) {
|
||||||
" negative effect on performance. (My test shows a 10% slowdown.)\n"
|
" negative effect on performance. (My test shows a 10% slowdown.)\n"
|
||||||
"--glx-copy-from-front\n"
|
"--glx-copy-from-front\n"
|
||||||
" GLX backend: Copy unmodified regions from front buffer instead of\n"
|
" GLX backend: Copy unmodified regions from front buffer instead of\n"
|
||||||
" redrawing them all. My tests show a 10% decrease in performance\n"
|
" redrawing them all. My tests with nvidia-drivers show a 10% decrease\n"
|
||||||
" when the whole screen is modified, but a 20% increase when only 1/4\n"
|
" in performance when the whole screen is modified, but a 20% increase\n"
|
||||||
" is, so this optimization is not enabled by default.\n"
|
" when only 1/4 is. My tests on nouveau show terrible slowdown.\n"
|
||||||
|
"--glx-use-copysubbuffermesa\n"
|
||||||
|
" GLX backend: Use MESA_copy_sub_buffer to do partial screen update.\n"
|
||||||
|
" My tests on nouveau shows a 200% performance boost when only 1/4 of\n"
|
||||||
|
" the screen is updated. May break VSync and is not available on some\n"
|
||||||
|
" drivers. Overrides --glx-copy-from-front.\n"
|
||||||
#undef WARNING
|
#undef WARNING
|
||||||
#ifndef CONFIG_DBUS
|
#ifndef CONFIG_DBUS
|
||||||
#define WARNING WARNING_DISABLED
|
#define WARNING WARNING_DISABLED
|
||||||
|
@ -4620,6 +4629,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
||||||
{ "glx-copy-from-front", no_argument, NULL, 292 },
|
{ "glx-copy-from-front", no_argument, NULL, 292 },
|
||||||
{ "benchmark", required_argument, NULL, 293 },
|
{ "benchmark", required_argument, NULL, 293 },
|
||||||
{ "benchmark-wid", required_argument, NULL, 294 },
|
{ "benchmark-wid", required_argument, NULL, 294 },
|
||||||
|
{ "glx-use-copysubbuffermesa", no_argument, NULL, 295 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -4898,6 +4908,10 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
||||||
// --benchmark-wid
|
// --benchmark-wid
|
||||||
ps->o.benchmark_wid = strtol(optarg, NULL, 0);
|
ps->o.benchmark_wid = strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case 295:
|
||||||
|
// --glx-use-copysubbuffermesa
|
||||||
|
ps->o.glx_use_copysubbuffermesa = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -427,10 +427,8 @@ dump_drawable(session_t *ps, Drawable drawable) {
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
win_is_fullscreen(session_t *ps, const win *w) {
|
win_is_fullscreen(session_t *ps, const win *w) {
|
||||||
return (w->a.x <= 0 && w->a.y <= 0
|
return rect_is_fullscreen(ps, w->a.x, w->a.y, w->widthb, w->heightb)
|
||||||
&& (w->a.x + w->widthb) >= ps->root_width
|
&& !w->bounding_shaped;
|
||||||
&& (w->a.y + w->heightb) >= ps->root_height
|
|
||||||
&& !w->bounding_shaped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
48
src/opengl.c
48
src/opengl.c
|
@ -96,6 +96,15 @@ glx_init(session_t *ps, bool need_render) {
|
||||||
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
|
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
|
||||||
goto glx_init_end;
|
goto glx_init_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps->o.glx_use_copysubbuffermesa) {
|
||||||
|
ps->glXCopySubBufferProc = (f_CopySubBuffer)
|
||||||
|
glXGetProcAddress((const GLubyte *) "glXCopySubBufferMESA");
|
||||||
|
if (!ps->glXCopySubBufferProc) {
|
||||||
|
printf_errf("(): Failed to acquire glXCopySubBufferMESA().");
|
||||||
|
goto glx_init_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire FBConfigs
|
// Acquire FBConfigs
|
||||||
|
@ -543,10 +552,13 @@ void
|
||||||
glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||||
ps->glx_z = 0.0;
|
ps->glx_z = 0.0;
|
||||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
// OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer,
|
// OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer,
|
||||||
// we currently redraw the whole screen or copy unmodified pixels from
|
// we could redraw the whole screen or copy unmodified pixels from
|
||||||
// front buffer with --glx-copy-from-front.
|
// front buffer with --glx-copy-from-front.
|
||||||
if (!ps->o.glx_copy_from_front || !*preg) {
|
if (ps->o.glx_use_copysubbuffermesa || !*preg) {
|
||||||
|
}
|
||||||
|
else if (!ps->o.glx_copy_from_front) {
|
||||||
free_region(ps, preg);
|
free_region(ps, preg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -612,7 +624,6 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||||
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
|
||||||
for (int i = 0; i < nrects; ++i) {
|
for (int i = 0; i < nrects; ++i) {
|
||||||
|
@ -853,6 +864,37 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap buffer with glXCopySubBufferMESA().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
|
||||||
|
int nrects = 0;
|
||||||
|
XRectangle *rects = XFixesFetchRegion(ps->dpy, reg, &nrects);
|
||||||
|
|
||||||
|
if (1 == nrects && rect_is_fullscreen(ps, rects[0].x, rects[0].y,
|
||||||
|
rects[0].width, rects[0].height)) {
|
||||||
|
glXSwapBuffers(ps->dpy, get_tgt_window(ps));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glx_set_clip(ps, None);
|
||||||
|
for (int i = 0; i < nrects; ++i) {
|
||||||
|
const int x = rects[i].x;
|
||||||
|
const int y = ps->root_height - rects[i].y - rects[i].height;
|
||||||
|
const int wid = rects[i].width;
|
||||||
|
const int hei = rects[i].height;
|
||||||
|
|
||||||
|
#ifdef DEBUG_GLX
|
||||||
|
printf_dbgf("(): %d, %d, %d, %d\n", x, y, wid, hei);
|
||||||
|
#endif
|
||||||
|
ps->glXCopySubBufferProc(ps->dpy, get_tgt_window(ps), x, y, wid, hei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rects)
|
||||||
|
XFree(rects);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
GLuint
|
GLuint
|
||||||
glx_create_shader(GLenum shader_type, const char *shader_str) {
|
glx_create_shader(GLenum shader_type, const char *shader_str) {
|
||||||
|
|
Loading…
Reference in New Issue