Skip to content

Commit

Permalink
Improvement: --glx-use-copysubbuffermesa
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
richardgv committed Mar 21, 2013
1 parent 8208ec6 commit 4b734c1
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ partially doing this out of a desire to learn Xlib.

## Changes from xcompmgr:

* OpenGL backend (`--backend glx`), in addition to the old X Render backend.
* __inactive window transparency / dimming__
* __titlebar/frame transparency__ (specified with `-e`)
* menu transparency (thanks to Dana)
Expand Down
17 changes: 15 additions & 2 deletions man/compton.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ OPTIONS
* '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-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.)
--
Expand Down Expand Up @@ -176,6 +177,18 @@ OPTIONS
*--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.

*--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*::
Enable remote control via D-Bus. See the *D-BUS API* section below for more details.

Expand Down Expand Up @@ -312,10 +325,10 @@ $ compton -c --shadow-red 1 --shadow-green 1 --shadow-blue 1
$ 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
Expand Down
18 changes: 18 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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.
typedef struct {
GLXFBConfig cfg;
Expand Down Expand Up @@ -344,6 +346,8 @@ typedef struct {
bool glx_no_stencil;
/// Whether to copy unmodified regions from front buffer.
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.
bool mark_wmwin_focused;
/// Whether to mark override-redirect windows as focused.
Expand Down Expand Up @@ -624,6 +628,8 @@ typedef struct {
f_BindTexImageEXT glXBindTexImageProc;
/// Pointer to glXReleaseTexImageEXT function.
f_ReleaseTexImageEXT glXReleaseTexImageProc;
/// Pointer to glXCopySubBufferMESA function.
f_CopySubBuffer glXCopySubBufferProc;
/// FBConfig-s for GLX pixmap of different depths.
glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1];
#ifdef CONFIG_VSYNC_OPENGL_GLSL
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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,
double opacity, bool neg, XserverRegion reg_tgt);

void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);

#ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint
glx_create_shader(GLenum shader_type, const char *shader_str);
Expand Down
24 changes: 19 additions & 5 deletions src/compton.c
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,6 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
}

// Free up all temporary regions
XFixesDestroyRegion(ps->dpy, region);
XFixesDestroyRegion(ps->dpy, reg_tmp);
XFixesDestroyRegion(ps->dpy, reg_tmp2);

Expand Down Expand Up @@ -1783,7 +1782,10 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
break;
#ifdef CONFIG_VSYNC_OPENGL
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;
#endif
default:
Expand All @@ -1802,6 +1804,8 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
}
#endif

XFixesDestroyRegion(ps->dpy, region);

#ifdef DEBUG_REPAINT
print_timestamp(ps);
struct timespec now = get_time_timespec();
Expand Down Expand Up @@ -4151,9 +4155,14 @@ usage(void) {
" negative effect on performance. (My test shows a 10% slowdown.)\n"
"--glx-copy-from-front\n"
" GLX backend: Copy unmodified regions from front buffer instead of\n"
" redrawing them all. My tests show a 10% decrease in performance\n"
" when the whole screen is modified, but a 20% increase when only 1/4\n"
" is, so this optimization is not enabled by default.\n"
" redrawing them all. My tests with nvidia-drivers show a 10% decrease\n"
" in performance when the whole screen is modified, but a 20% increase\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
#ifndef CONFIG_DBUS
#define WARNING WARNING_DISABLED
Expand Down Expand Up @@ -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 },
{ "benchmark", required_argument, NULL, 293 },
{ "benchmark-wid", required_argument, NULL, 294 },
{ "glx-use-copysubbuffermesa", no_argument, NULL, 295 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
Expand Down Expand Up @@ -4898,6 +4908,10 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
// --benchmark-wid
ps->o.benchmark_wid = strtol(optarg, NULL, 0);
break;
case 295:
// --glx-use-copysubbuffermesa
ps->o.glx_use_copysubbuffermesa = true;
break;
default:
usage();
break;
Expand Down
6 changes: 2 additions & 4 deletions src/compton.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,8 @@ dump_drawable(session_t *ps, Drawable drawable) {
*/
static inline bool
win_is_fullscreen(session_t *ps, const win *w) {
return (w->a.x <= 0 && w->a.y <= 0
&& (w->a.x + w->widthb) >= ps->root_width
&& (w->a.y + w->heightb) >= ps->root_height
&& !w->bounding_shaped);
return rect_is_fullscreen(ps, w->a.x, w->a.y, w->widthb, w->heightb)
&& !w->bounding_shaped;
}

static void
Expand Down
48 changes: 45 additions & 3 deletions src/opengl.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ glx_init(session_t *ps, bool need_render) {
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
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
Expand Down Expand Up @@ -543,10 +552,13 @@ void
glx_paint_pre(session_t *ps, XserverRegion *preg) {
ps->glx_z = 0.0;
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// 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.
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);
}
else {
Expand Down Expand Up @@ -612,7 +624,6 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
glDepthMask(GL_FALSE);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);


glBegin(GL_QUADS);

for (int i = 0; i < nrects; ++i) {
Expand Down Expand Up @@ -853,6 +864,37 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
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
GLuint
glx_create_shader(GLenum shader_type, const char *shader_str) {
Expand Down

0 comments on commit 4b734c1

Please sign in to comment.