Bug fix: GLX: Fix --inactive-dim & fix color inversion

- GLX backend: Fix broken --inactive-dim.

- GLX backend: Fix bugs when inverting colors of windows. Thanks to
  madsy and neure for help.

- GLX backend: Lift `glx_no_stencil` restriction from glx_init_blur().
  It still probably won't work, but the user can try.

- XRender backend: Use XRenderFillRectangles() instead of
  XRenderComposite() to do dimming.
This commit is contained in:
Richard Grenville 2013-03-25 11:36:39 +08:00
parent 75912d23f3
commit 9e607b2543
3 changed files with 162 additions and 30 deletions

View File

@ -878,9 +878,6 @@ typedef struct _win {
// Dim-related members
/// Whether the window is to be dimmed.
bool dim;
/// Picture for dimming. Affected by user-specified inactive dim
/// opacity and window opacity.
Picture dim_alpha_pict;
/// Whether to invert window color.
bool invert_color;
@ -1641,6 +1638,10 @@ bool
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center);
bool
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor);
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,

View File

@ -1192,16 +1192,6 @@ paint_preprocess(session_t *ps, win *list) {
if (w->shadow && !paint_isvalid(ps, &w->shadow_paint))
win_build_shadow(ps, w, 1);
// Dimming preprocessing
if (w->dim) {
double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed)
dim_opacity *= get_opacity_percent(w);
w->dim_alpha_pict = get_alpha_pict_d(ps, dim_opacity);
}
}
if ((to_paint && WMODE_SOLID == w->mode)
@ -1562,10 +1552,38 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint) {
free_picture(ps, &pict);
// Dimming the window if needed
if (BKEND_XRENDER == ps->o.backend
&& w->dim && w->dim_alpha_pict != ps->alpha_picts[0]) {
XRenderComposite(ps->dpy, PictOpOver, ps->black_picture,
w->dim_alpha_pict, ps->tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
if (w->dim) {
double dim_opacity = ps->o.inactive_dim;
if (!ps->o.inactive_dim_fixed)
dim_opacity *= get_opacity_percent(w);
switch (ps->o.backend) {
case BKEND_XRENDER:
{
unsigned short cval = 0xffff * dim_opacity;
// Premultiply color
XRenderColor color = {
.red = 0, .green = 0, .blue = 0, .alpha = cval,
};
XRectangle rect = {
.x = x,
.y = y,
.width = wid,
.height = hei,
};
XRenderFillRectangles(ps->dpy, PictOpOver, ps->tgt_buffer, &color,
&rect, 1);
}
break;
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
glx_dim_dst(ps, x, y, wid, hei, ps->glx_z - 0.7, dim_opacity);
break;
#endif
}
}
}
@ -2584,7 +2602,6 @@ add_win(session_t *ps, Window id, Window prev) {
.prop_shadow = -1,
.dim = false,
.dim_alpha_pict = None,
.invert_color = false,
.invert_color_force = UNSET,
@ -4174,6 +4191,8 @@ usage(void) {
"--blur-background-fixed\n"
" Use fixed blur strength instead of adjusting according to window\n"
" opacity.\n"
"--blur-background-exclude condition\n"
" Exclude conditions for background blur.\n"
"--invert-color-include condition\n"
" Specify a list of conditions of windows that should be painted with\n"
" inverted color. Resource-hogging, and is not well tested.\n"

View File

@ -194,7 +194,6 @@ glx_init_blur(session_t *ps) {
if (ps->o.glx_no_stencil) {
printf_errf("(): I'm afraid blur background won't work so well without "
"stencil buffer support.");
return false;
}
// Build shader
@ -738,6 +737,37 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
return true;
}
bool
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor) {
// It's possible to dim in glx_render(), but it would be over-complicated
// considering all those mess in color negation and modulation
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, factor);
glBegin(GL_QUADS);
{
GLint rdx = dx;
GLint rdy = ps->root_height - dy;
GLint rdxe = rdx + width;
GLint rdye = rdy - height;
glVertex3i(rdx, rdy, z);
glVertex3i(rdxe, rdy, z);
glVertex3i(rdxe, rdye, z);
glVertex3i(rdx, rdye, z);
}
glEnd();
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
glDisable(GL_BLEND);
return true;
}
/**
* @brief Render a region with texture data.
*/
@ -750,16 +780,23 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
return false;
}
const bool argb = (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->glx_fbconfigs[ptex->depth]->texture_fmt);
bool dual_texture = false;
// It's required by legacy versions of OpenGL to enable texture target
// before specifying environment. Thanks to madsy for telling me.
glEnable(ptex->target);
// Enable blending if needed
if (opacity < 1.0 || GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->glx_fbconfigs[ptex->depth]->texture_fmt) {
if (opacity < 1.0 || argb) {
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 premulitplied ARGB format, and
// This is all weird, but X Render is using premultiplied 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);
@ -772,11 +809,68 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_COPY_INVERTED);
}
// Blending color negation
// ARGB texture color negation
else if (argb) {
dual_texture = true;
// Use two texture stages because the calculation is too complicated,
// thanks to madsy for providing code
// Texture stage 0
glActiveTexture(GL_TEXTURE0);
// Negation for premultiplied color: color = A - C
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Pass texture alpha through
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
// Texture stage 1
glActiveTexture(GL_TEXTURE1);
glEnable(ptex->target);
glBindTexture(ptex->target, ptex->texture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
}
// RGB blend color negation
else {
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);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
}
}
@ -807,8 +901,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects);
}
glEnable(ptex->target);
glBindTexture(ptex->target, ptex->texture);
if (dual_texture) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(ptex->target, ptex->texture);
glActiveTexture(GL_TEXTURE0);
}
glBegin(GL_QUADS);
@ -833,16 +931,23 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
printf_dbgf("(): Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d\n", i, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
#endif
glTexCoord2f(rx, ry);
#define P_TEXCOORD(cx, cy) { \
if (dual_texture) { \
glMultiTexCoord2f(GL_TEXTURE0, cx, cy); \
glMultiTexCoord2f(GL_TEXTURE1, cx, cy); \
} \
else glTexCoord2f(cx, cy); \
}
P_TEXCOORD(rx, ry);
glVertex3i(rdx, rdy, z);
glTexCoord2f(rxe, ry);
P_TEXCOORD(rxe, ry);
glVertex3i(rdxe, rdy, z);
glTexCoord2f(rxe, rye);
P_TEXCOORD(rxe, rye);
glVertex3i(rdxe, rdye, z);
glTexCoord2f(rx, rye);
P_TEXCOORD(rx, rye);
glVertex3i(rdx, rdye, z);
}
@ -861,6 +966,13 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glDisable(GL_COLOR_LOGIC_OP);
glDisable(ptex->target);
if (dual_texture) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(ptex->target, 0);
glDisable(ptex->target);
glActiveTexture(GL_TEXTURE0);
}
return true;
}