Improvement: --glx-copy-from-front & benchmark mode
- GLX backend: Add --glx-copy-front, which copies all unmodified regions from front buffer to back buffer instead of redrawing the whole screen. Unfortunately, probably because glCopyPixels() isn't usually well-optimized on graphic cards, this option appears very unstable in its effect: Over 20% boost in performance when only 1/4 of the screen is modified, but 10% decrease when the whole screen is. Thus, not enabled by default. - GLX backend: Add glx_blur_dst(), to prepare for the background blur feature. It currently is capable to modify background in the desired way, but the core blur shader is absent. glConvolution2D() seemingly relies entirely on CPU and has horrifying performance. I've hesitating about whether I should use ARB assembly language or GLSL for the shader. - GLX backend: Invert y-axis GL matrix. It's upside-down previously because that's what dcompmgr uses. Seemingly a "normal" y-axis is required for glCopyPixels() to operate correctly. - GLX backend: Fix some GLX_TEXTURE_RECTANGLE compatibility issues. Still, not actually tested. - Add benchmark mode (--benchmark & --benchmark-wid). - Misc changes.
This commit is contained in:
parent
a41f05ea92
commit
725bc40a65
10
src/common.h
10
src/common.h
|
@ -297,6 +297,7 @@ struct _glx_texture {
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
GLXPixmap glpixmap;
|
GLXPixmap glpixmap;
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
|
GLenum target;
|
||||||
unsigned width;
|
unsigned width;
|
||||||
unsigned height;
|
unsigned height;
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
|
@ -341,6 +342,8 @@ typedef struct {
|
||||||
enum backend backend;
|
enum backend backend;
|
||||||
/// Whether to avoid using stencil buffer under GLX backend. Might be unsafe.
|
/// Whether to avoid using stencil buffer under GLX backend. Might be unsafe.
|
||||||
bool glx_no_stencil;
|
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.
|
/// 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.
|
||||||
|
@ -359,6 +362,10 @@ typedef struct {
|
||||||
bool dbus;
|
bool dbus;
|
||||||
/// Path to log file.
|
/// Path to log file.
|
||||||
char *logpath;
|
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.
|
/// Whether to work under synchronized mode for debugging.
|
||||||
bool synchronize;
|
bool synchronize;
|
||||||
|
|
||||||
|
@ -1578,6 +1585,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
void
|
void
|
||||||
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
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.
|
* Check if a texture is binded, or is binded to the given pixmap.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1569,12 +1569,8 @@ paint_all(session_t *ps, XserverRegion region, win *t) {
|
||||||
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
|
XserverRegion reg_paint = None, reg_tmp = None, reg_tmp2 = None;
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
// GLX backend: OpenGL doesn't support partial repaint without
|
|
||||||
// GLX_MESA_copy_sub_buffer
|
|
||||||
if (BKEND_GLX == ps->o.backend) {
|
if (BKEND_GLX == ps->o.backend) {
|
||||||
free_region(ps, ®ion);
|
glx_paint_pre(ps, ®ion);
|
||||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
ps->glx_z = 0.0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -4134,9 +4130,14 @@ usage(void) {
|
||||||
"--backend backend\n"
|
"--backend backend\n"
|
||||||
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
|
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
|
||||||
"--glx-no-stencil\n"
|
"--glx-no-stencil\n"
|
||||||
" Avoid using stencil buffer under GLX backend. Might cause issues\n"
|
" GLX backend: Avoid using stencil buffer. Might cause issues\n"
|
||||||
" when rendering transparent content, may have a positive or\n"
|
" when rendering transparent content. May have a positive or\n"
|
||||||
" 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 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
|
#undef WARNING
|
||||||
#ifndef CONFIG_DBUS
|
#ifndef CONFIG_DBUS
|
||||||
#define WARNING WARNING_DISABLED
|
#define WARNING WARNING_DISABLED
|
||||||
|
@ -4145,7 +4146,13 @@ usage(void) {
|
||||||
#endif
|
#endif
|
||||||
"--dbus\n"
|
"--dbus\n"
|
||||||
" Enable remote control via D-Bus. See the D-BUS API section in the\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);
|
fputs(usage_text , stderr);
|
||||||
#undef WARNING
|
#undef WARNING
|
||||||
#undef WARNING_DISABLED
|
#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 },
|
{ "opengl", no_argument, NULL, 289 },
|
||||||
{ "backend", required_argument, NULL, 290 },
|
{ "backend", required_argument, NULL, 290 },
|
||||||
{ "glx-no-stencil", no_argument, NULL, 291 },
|
{ "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
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
@ -4860,6 +4870,18 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
||||||
// --glx-no-stencil
|
// --glx-no-stencil
|
||||||
ps->o.glx_no_stencil = true;
|
ps->o.glx_no_stencil = true;
|
||||||
break;
|
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:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
|
@ -5575,7 +5597,7 @@ mainloop(session_t *ps) {
|
||||||
struct timeval *ptv = NULL;
|
struct timeval *ptv = NULL;
|
||||||
{
|
{
|
||||||
// Consider ev_received firstly
|
// Consider ev_received firstly
|
||||||
if (ps->ev_received) {
|
if (ps->ev_received || ps->o.benchmark) {
|
||||||
ptv = malloc(sizeof(struct timeval));
|
ptv = malloc(sizeof(struct timeval));
|
||||||
ptv->tv_sec = 0L;
|
ptv->tv_sec = 0L;
|
||||||
ptv->tv_usec = 0L;
|
ptv->tv_usec = 0L;
|
||||||
|
@ -5658,6 +5680,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.display = NULL,
|
.display = NULL,
|
||||||
.backend = BKEND_XRENDER,
|
.backend = BKEND_XRENDER,
|
||||||
.glx_no_stencil = false,
|
.glx_no_stencil = false,
|
||||||
|
.glx_copy_from_front = false,
|
||||||
.mark_wmwin_focused = false,
|
.mark_wmwin_focused = false,
|
||||||
.mark_ovredir_focused = false,
|
.mark_ovredir_focused = false,
|
||||||
.fork_after_register = false,
|
.fork_after_register = false,
|
||||||
|
@ -5666,6 +5689,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.paint_on_overlay = false,
|
.paint_on_overlay = false,
|
||||||
.unredir_if_possible = false,
|
.unredir_if_possible = false,
|
||||||
.dbus = false,
|
.dbus = false,
|
||||||
|
.benchmark = 0,
|
||||||
|
.benchmark_wid = None,
|
||||||
.logpath = NULL,
|
.logpath = NULL,
|
||||||
|
|
||||||
.refresh_rate = 0,
|
.refresh_rate = 0,
|
||||||
|
@ -6249,6 +6274,21 @@ session_run(session_t *ps) {
|
||||||
while (mainloop(ps))
|
while (mainloop(ps))
|
||||||
continue;
|
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
|
// idling will be turned off during paint_preprocess() if needed
|
||||||
ps->idling = true;
|
ps->idling = true;
|
||||||
|
|
||||||
|
@ -6263,6 +6303,8 @@ session_run(session_t *ps) {
|
||||||
paint_all(ps, ps->all_damage, t);
|
paint_all(ps, ps->all_damage, t);
|
||||||
ps->reg_ignore_expire = false;
|
ps->reg_ignore_expire = false;
|
||||||
paint++;
|
paint++;
|
||||||
|
if (ps->o.benchmark && paint >= ps->o.benchmark)
|
||||||
|
exit(0);
|
||||||
XSync(ps->dpy, False);
|
XSync(ps->dpy, False);
|
||||||
ps->all_damage = None;
|
ps->all_damage = None;
|
||||||
}
|
}
|
||||||
|
|
199
src/opengl.c
199
src/opengl.c
|
@ -163,7 +163,7 @@ glx_on_root_change(session_t *ps) {
|
||||||
// Initialize matrix, copied from dcompmgr
|
// Initialize matrix, copied from dcompmgr
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
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);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,6 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GLenum target = GL_TEXTURE_2D;
|
|
||||||
glx_texture_t *ptex = *pptex;
|
glx_texture_t *ptex = *pptex;
|
||||||
bool need_release = true;
|
bool need_release = true;
|
||||||
|
|
||||||
|
@ -338,6 +337,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
.texture = 0,
|
.texture = 0,
|
||||||
.glpixmap = 0,
|
.glpixmap = 0,
|
||||||
.pixmap = 0,
|
.pixmap = 0,
|
||||||
|
.target = 0,
|
||||||
.width = 0,
|
.width = 0,
|
||||||
.height = 0,
|
.height = 0,
|
||||||
.depth = 0,
|
.depth = 0,
|
||||||
|
@ -350,37 +350,11 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
*pptex = ptex;
|
*pptex = ptex;
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnable(target);
|
|
||||||
|
|
||||||
// Release pixmap if parameters are inconsistent
|
// Release pixmap if parameters are inconsistent
|
||||||
if (ptex->texture && ptex->pixmap != pixmap) {
|
if (ptex->texture && ptex->pixmap != pixmap) {
|
||||||
glx_release_pixmap(ps, ptex);
|
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
|
// Create GLX pixmap
|
||||||
if (!ptex->glpixmap) {
|
if (!ptex->glpixmap) {
|
||||||
need_release = false;
|
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
|
// 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
|
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
|
||||||
&& ps->glx_has_texture_non_power_of_two)
|
&& ps->glx_has_texture_non_power_of_two)
|
||||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
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->glpixmap = glXCreatePixmap(ps->dpy, pcfg->cfg, pixmap, attrs);
|
||||||
ptex->pixmap = pixmap;
|
ptex->pixmap = pixmap;
|
||||||
|
ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D:
|
||||||
|
GL_TEXTURE_RECTANGLE);
|
||||||
ptex->width = width;
|
ptex->width = width;
|
||||||
ptex->height = height;
|
ptex->height = height;
|
||||||
ptex->depth = depth;
|
ptex->depth = depth;
|
||||||
|
@ -445,6 +423,32 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
return false;
|
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...
|
// The specification requires rebinding whenever the content changes...
|
||||||
// We can't follow this, too slow.
|
// We can't follow this, too slow.
|
||||||
if (need_release)
|
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);
|
ps->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
glBindTexture(target, 0);
|
glBindTexture(ptex->target, 0);
|
||||||
glDisable(target);
|
glDisable(ptex->target);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -466,9 +470,9 @@ void
|
||||||
glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
||||||
// Release binding
|
// Release binding
|
||||||
if (ptex->glpixmap && ptex->texture) {
|
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);
|
ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(ptex->target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free GLX Pixmap
|
// Free GLX Pixmap
|
||||||
|
@ -478,6 +482,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, ®_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.
|
* Set clipping region on the target window.
|
||||||
*/
|
*/
|
||||||
|
@ -524,9 +563,9 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
|
||||||
|
|
||||||
for (int i = 0; i < nrects; ++i) {
|
for (int i = 0; i < nrects; ++i) {
|
||||||
GLint rx = rects[i].x;
|
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 rxe = rx + rects[i].width;
|
||||||
GLint rye = ry + rects[i].height;
|
GLint rye = ry - rects[i].height;
|
||||||
GLint z = 0;
|
GLint z = 0;
|
||||||
|
|
||||||
#ifdef DEBUG_GLX
|
#ifdef DEBUG_GLX
|
||||||
|
@ -550,6 +589,78 @@ glx_set_clip(session_t *ps, XserverRegion reg) {
|
||||||
XFree(rects);
|
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.
|
* @brief Render a region with texture data.
|
||||||
*/
|
*/
|
||||||
|
@ -557,6 +668,8 @@ bool
|
||||||
glx_render(session_t *ps, const glx_texture_t *ptex,
|
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) {
|
||||||
|
bool blur_background = false;
|
||||||
|
|
||||||
if (!ptex || !ptex->texture) {
|
if (!ptex || !ptex->texture) {
|
||||||
printf_errf("(): Missing texture.");
|
printf_errf("(): Missing texture.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -565,12 +678,15 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
// Enable blending if needed
|
// Enable blending if needed
|
||||||
if (opacity < 1.0 || GLX_TEXTURE_FORMAT_RGBA_EXT ==
|
if (opacity < 1.0 || GLX_TEXTURE_FORMAT_RGBA_EXT ==
|
||||||
ps->glx_fbconfigs[ptex->depth]->texture_fmt) {
|
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);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
// Needed for handling opacity of ARGB texture
|
// Needed for handling opacity of ARGB texture
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
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.
|
// we need to use those things to correct it. Thanks to derhass for help.
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glColor4f(opacity, opacity, opacity, opacity);
|
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);
|
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects);
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(ptex->target);
|
||||||
glBindTexture(GL_TEXTURE_2D, ptex->texture);
|
glBindTexture(ptex->target, ptex->texture);
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
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 rxe = rx + (double) rects[i].width / ptex->width;
|
||||||
GLfloat rye = ry + (double) rects[i].height / ptex->height;
|
GLfloat rye = ry + (double) rects[i].height / ptex->height;
|
||||||
GLint rdx = rects[i].x;
|
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 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
|
// Invert Y if needed, this may not work as expected, though. I don't
|
||||||
// have such a FBConfig to test with.
|
// have such a FBConfig to test with.
|
||||||
|
@ -665,11 +781,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(ptex->target, 0);
|
||||||
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glDisable(GL_COLOR_LOGIC_OP);
|
glDisable(GL_COLOR_LOGIC_OP);
|
||||||
|
glDisable(ptex->target);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue