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.
pull/2/head
Richard Grenville 12 years ago
parent da85de48a9
commit 2dfe9d52ed

@ -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

@ -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…
Cancel
Save