summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common.h10
-rw-r--r--compton.c60
-rw-r--r--opengl.c199
3 files changed, 219 insertions, 50 deletions
diff --git a/common.h b/common.h
index 3b6620854..978a9ecb8 100644
--- a/common.h
+++ b/common.h
@@ -297,6 +297,7 @@ struct _glx_texture {
GLuint texture;
GLXPixmap glpixmap;
Pixmap pixmap;
+ GLenum target;
unsigned width;
unsigned height;
unsigned depth;
@@ -341,6 +342,8 @@ typedef struct {
enum backend backend;
/// Whether to avoid using stencil buffer under GLX backend. Might be unsafe.
bool glx_no_stencil;
+ /// Whether to copy unmodified regions from front buffer.
+ bool glx_copy_from_front;
/// Whether to try to detect WM windows and mark them as focused.
bool mark_wmwin_focused;
/// Whether to mark override-redirect windows as focused.
@@ -359,6 +362,10 @@ typedef struct {
bool dbus;
/// Path to log file.
char *logpath;
+ /// Number of cycles to paint in benchmark mode. 0 for disabled.
+ int benchmark;
+ /// Window to constantly repaint in benchmark mode. 0 for full-screen.
+ Window benchmark_wid;
/// Whether to work under synchronized mode for debugging.
bool synchronize;
@@ -1578,6 +1585,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
void
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
+void
+glx_paint_pre(session_t *ps, XserverRegion *preg);
+
/**
* Check if a texture is binded, or is binded to the given pixmap.
*/
diff --git a/compton.c b/compton.c
index a2fbee265..2b1ca9204 100644
--- a/compton.c
+++ b/compton.c
@@ -1569,12 +1569,8 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
#ifdef CONFIG_VSYNC_OPENGL
- // GLX backend: OpenGL doesn't support partial repaint without
- // GLX_MESA_copy_sub_buffer
if (BKEND_GLX == ps->o.backend) {
- free_region(ps, &region);
- // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- ps->glx_z = 0.0;
+ glx_paint_pre(ps, &region);
}
#endif
@@ -4134,9 +4130,14 @@ usage(void) {
"--backend backend\n"
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
"--glx-no-stencil\n"
- " Avoid using stencil buffer under GLX backend. Might cause issues\n"
- " when rendering transparent content, may have a positive or\n"
+ " GLX backend: Avoid using stencil buffer. Might cause issues\n"
+ " when rendering transparent content. May have a positive or\n"
" 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"
#undef WARNING
#ifndef CONFIG_DBUS
#define WARNING WARNING_DISABLED
@@ -4145,7 +4146,13 @@ usage(void) {
#endif
"--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
- " man page for more details." WARNING "\n";
+ " man page for more details." WARNING "\n"
+ "--benchmark cycles\n"
+ " Benchmark mode. Repeatedly paint until reaching the specified cycles.\n"
+ "--benchmark-wid window-id\n"
+ " Specify window ID to repaint in benchmark mode. If omitted or is 0,\n"
+ " the whole screen is repainted.\n"
+ ;
fputs(usage_text , stderr);
#undef WARNING
#undef WARNING_DISABLED
@@ -4594,6 +4601,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "opengl", no_argument, NULL, 289 },
{ "backend", required_argument, NULL, 290 },
{ "glx-no-stencil", no_argument, NULL, 291 },
+ { "glx-copy-from-front", no_argument, NULL, 292 },
+ { "benchmark", required_argument, NULL, 293 },
+ { "benchmark-wid", required_argument, NULL, 294 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
@@ -4860,6 +4870,18 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
// --glx-no-stencil
ps->o.glx_no_stencil = true;
break;
+ case 292:
+ // --glx-copy-from-front
+ ps->o.glx_copy_from_front = true;
+ break;
+ case 293:
+ // --benchmark
+ ps->o.benchmark = atoi(optarg);
+ break;
+ case 294:
+ // --benchmark-wid
+ ps->o.benchmark_wid = strtol(optarg, NULL, 0);
+ break;
default:
usage();
break;
@@ -5575,7 +5597,7 @@ mainloop(session_t *ps) {
struct timeval *ptv = NULL;
{
// Consider ev_received firstly
- if (ps->ev_received) {
+ if (ps->ev_received || ps->o.benchmark) {
ptv = malloc(sizeof(struct timeval));
ptv->tv_sec = 0L;
ptv->tv_usec = 0L;
@@ -5658,6 +5680,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
.display = NULL,
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
+ .glx_copy_from_front = false,
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,
.fork_after_register = false,
@@ -5666,6 +5689,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
.paint_on_overlay = false,
.unredir_if_possible = false,
.dbus = false,
+ .benchmark = 0,
+ .benchmark_wid = None,
.logpath = NULL,
.refresh_rate = 0,
@@ -6249,6 +6274,21 @@ session_run(session_t *ps) {
while (mainloop(ps))
continue;
+ if (ps->o.benchmark) {
+ if (ps->o.benchmark_wid) {
+ win *w = find_win(ps, ps->o.benchmark_wid);
+ if (!w) {
+ printf_errf("(): Couldn't find specified benchmark window.");
+ session_destroy(ps);
+ exit(1);
+ }
+ add_damage_win(ps, w);
+ }
+ else {
+ force_repaint(ps);
+ }
+ }
+
// idling will be turned off during paint_preprocess() if needed
ps->idling = true;
@@ -6263,6 +6303,8 @@ session_run(session_t *ps) {
paint_all(ps, ps->all_damage, t);
ps->reg_ignore_expire = false;
paint++;
+ if (ps->o.benchmark && paint >= ps->o.benchmark)
+ exit(0);
XSync(ps->dpy, False);
ps->all_damage = None;
}
diff --git a/opengl.c b/opengl.c
index 92b0292b0..eca91667b 100644
--- a/opengl.c
+++ b/opengl.c
@@ -163,7 +163,7 @@ glx_on_root_change(session_t *ps) {
// Initialize matrix, copied from dcompmgr
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- glOrtho(0, ps->root_width, ps->root_height, 0, -100.0, 100.0);
+ glOrtho(0, ps->root_width, 0, ps->root_height, -1000.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
@@ -328,7 +328,6 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
return false;
}
- const GLenum target = GL_TEXTURE_2D;
glx_texture_t *ptex = *pptex;
bool need_release = true;
@@ -338,6 +337,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
.texture = 0,
.glpixmap = 0,
.pixmap = 0,
+ .target = 0,
.width = 0,
.height = 0,
.depth = 0,
@@ -350,37 +350,11 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
*pptex = ptex;
}
- glEnable(target);
-
// Release pixmap if parameters are inconsistent
if (ptex->texture && ptex->pixmap != pixmap) {
glx_release_pixmap(ps, ptex);
}
- // Create texture
- if (!ptex->texture) {
- need_release = false;
-
- GLuint texture = 0;
- glGenTextures(1, &texture);
- glBindTexture(target, texture);
-
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glBindTexture(target, 0);
-
- ptex->texture = texture;
- }
- if (!ptex->texture) {
- printf_errf("(): Failed to allocate texture.");
- return false;
- }
-
- glBindTexture(target, ptex->texture);
-
// Create GLX pixmap
if (!ptex->glpixmap) {
need_release = false;
@@ -409,7 +383,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
}
// Determine texture target, copied from compiz
- GLint tex_tgt = 0;
+ // The assumption we made here is the target never changes based on any
+ // pixmap-specific parameters, and this may change in the future
+ GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
&& ps->glx_has_texture_non_power_of_two)
tex_tgt = GLX_TEXTURE_2D_EXT;
@@ -435,6 +411,8 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
ptex->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs);
ptex->pixmap = pixmap;
+ ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
+ GL_TEXTURE_RECTANGLE);
ptex->width = width;
ptex->height = height;
ptex->depth = depth;
@@ -445,6 +423,32 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
return false;
}
+ glEnable(ptex->target);
+
+ // Create texture
+ if (!ptex->texture) {
+ need_release = false;
+
+ GLuint texture = 0;
+ glGenTextures(1, &texture);
+ glBindTexture(ptex->target, texture);
+
+ glTexParameteri(ptex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(ptex->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(ptex->target, 0);
+
+ ptex->texture = texture;
+ }
+ if (!ptex->texture) {
+ printf_errf("(): Failed to allocate texture.");
+ return false;
+ }
+
+ glBindTexture(ptex->target, ptex->texture);
+
// The specification requires rebinding whenever the content changes...
// We can't follow this, too slow.
if (need_release)
@@ -453,8 +457,8 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
ps->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
// Cleanup
- glBindTexture(target, 0);
- glDisable(target);
+ glBindTexture(ptex->target, 0);
+ glDisable(ptex->target);
return true;
}
@@ -466,9 +470,9 @@ void
glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
// Release binding
if (ptex->glpixmap && ptex->texture) {
- glBindTexture(GL_TEXTURE_2D, ptex->texture);
+ glBindTexture(ptex->target, ptex->texture);
ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
- glBindTexture(GL_TEXTURE_2D, 0);
+ glBindTexture(ptex->target, 0);
}
// Free GLX Pixmap
@@ -479,6 +483,41 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
}
/**
+ * Preprocess function before start painting.
+ */
+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
+ // front buffer with --glx-copy-from-front.
+ if (!ps->o.glx_copy_from_front || !*preg) {
+ free_region(ps, preg);
+ }
+ else {
+ {
+ XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
+ XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
+ glx_set_clip(ps, reg_copy);
+ free_region(ps, &reg_copy);
+ }
+
+ {
+ GLfloat raster_pos[4];
+ glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
+ glReadBuffer(GL_FRONT);
+ glRasterPos2f(0.0, 0.0);
+ glCopyPixels(0, 0, ps->root_width, ps->root_height, GL_COLOR);
+ glReadBuffer(GL_BACK);
+ glRasterPos4fv(raster_pos);
+ }
+ }
+
+ glx_set_clip(ps, *preg);
+}
+
+/**
* Set clipping region on the target window.
*/
void
@@ -524,9 +563,9 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
for (int i = 0; i < nrects; ++i) {
GLint rx = rects[i].x;
- GLint ry = rects[i].y;
+ GLint ry = ps->root_height - rects[i].y;
GLint rxe = rx + rects[i].width;
- GLint rye = ry + rects[i].height;
+ GLint rye = ry - rects[i].height;
GLint z = 0;
#ifdef DEBUG_GLX
@@ -550,6 +589,78 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
XFree(rects);
}
+bool
+glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z) {
+ // Read destination pixels into a texture
+ GLuint tex_scr = 0;
+ glGenTextures(1, &tex_scr);
+ if (!tex_scr) {
+ printf_errf("(): Failed to allocate texture.");
+ return false;
+ }
+
+ GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
+ if (ps->glx_has_texture_non_power_of_two)
+ tex_tgt = GL_TEXTURE_2D;
+
+ glEnable(tex_tgt);
+ glBindTexture(tex_tgt, tex_scr);
+ glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(tex_tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(tex_tgt, 0, GL_RGB, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ glCopyTexSubImage2D(tex_tgt, 0, 0, 0, dx, ps->root_height - dy - height, width, height);
+
+#ifdef DEBUG_GLX
+ printf_dbgf("(): %d, %d, %d, %d\n", dx, ps->root_height - dy - height, width, height);
+#endif
+
+ // Paint it back
+ // TODO: Blur function. We are using color negation for testing now.
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+ glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
+
+ glBegin(GL_QUADS);
+
+ {
+ const GLfloat rx = 0.0;
+ const GLfloat ry = 1.0;
+ const GLfloat rxe = 1.0;
+ const GLfloat rye = 0.0;
+ const GLint rdx = dx;
+ const GLint rdy = ps->root_height - dy;
+ const GLint rdxe = rdx + width;
+ const GLint rdye = rdy - height;
+
+#ifdef DEBUG_GLX
+ printf_dbgf("(): %f, %f, %f, %f -> %d, %d, %d, %d\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
+#endif
+
+ glTexCoord2f(rx, ry);
+ glVertex3f(rdx, rdy, z);
+
+ glTexCoord2f(rxe, ry);
+ glVertex3f(rdxe, rdy, z);
+
+ glTexCoord2f(rxe, rye);
+ glVertex3f(rdxe, rdye, z);
+
+ glTexCoord2f(rx, rye);
+ glVertex3f(rdx, rdye, z);
+ }
+
+ glEnd();
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glBindTexture(tex_tgt, 0);
+ glDeleteTextures(1, &tex_scr);
+ glDisable(tex_tgt);
+
+ return true;
+}
+
/**
* @brief Render a region with texture data.
*/
@@ -557,6 +668,8 @@ bool
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) {
+ bool blur_background = false;
+
if (!ptex || !ptex->texture) {
printf_errf("(): Missing texture.");
return false;
@@ -565,12 +678,15 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
// Enable blending if needed
if (opacity < 1.0 || GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->glx_fbconfigs[ptex->depth]->texture_fmt) {
+ if (!ps->o.glx_no_stencil && blur_background)
+ glx_blur_dst(ps, dx, dy, width, height, z - 0.5);
+
glEnable(GL_BLEND);
// Needed for handling opacity of ARGB texture
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- // This is all weird, but X Render is using a strange ARGB format, and
+ // This is all weird, but X Render is using premulitplied ARGB format, and
// we need to use those things to correct it. Thanks to derhass for help.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(opacity, opacity, opacity, opacity);
@@ -618,8 +734,8 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects);
}
- glEnable(GL_TEXTURE_2D);
- glBindTexture(GL_TEXTURE_2D, ptex->texture);
+ glEnable(ptex->target);
+ glBindTexture(ptex->target, ptex->texture);
glBegin(GL_QUADS);
@@ -629,9 +745,9 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
GLfloat rxe = rx + (double) rects[i].width / ptex->width;
GLfloat rye = ry + (double) rects[i].height / ptex->height;
GLint rdx = rects[i].x;
- GLint rdy = rects[i].y;
+ GLint rdy = ps->root_height - rects[i].y;
GLint rdxe = rdx + rects[i].width;
- GLint rdye = rdy + rects[i].height;
+ GLint rdye = rdy - rects[i].height;
// Invert Y if needed, this may not work as expected, though. I don't
// have such a FBConfig to test with.
@@ -665,11 +781,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
}
// Cleanup
- glBindTexture(GL_TEXTURE_2D, 0);
+ glBindTexture(ptex->target, 0);
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDisable(GL_BLEND);
glDisable(GL_COLOR_LOGIC_OP);
+ glDisable(ptex->target);
return true;
}