Imp: Multi-pass blur & D-Bus fading control
- Add multipass blur support. Note GLX Framebuffer support is required. My benchmark shows multipass blur brings 5% performance boost for X Render backend (3x3box). On GLX backend it brings 10% performance boost for 5x5box but negatively affects performance for 3x3box. Thanks to jrfonseca for advice. (#107) - GLX backend: Cache blur texture for each window, for a 12% performance boost. - Add D-Bus fading control. Thanks to yulan6248 for testing. (#112) - Fix FAQ link in README.md. Thanks to lorenzos for report. (#111) - Correctly deinitialize VSync on on-the-fly VSync method switch. - X Render backend: Normalize blur kernel. - Code clean-up. - Known issue: Linear corruption on border of a window may appear with X Render multi-pass blur. Possible to fix but probably not worthwhile.
This commit is contained in:
parent
1b34dc3a9a
commit
07bc7485c3
8
Makefile
8
Makefile
@ -52,6 +52,12 @@ ifeq "$(NO_VSYNC_OPENGL)" ""
|
|||||||
ifeq "$(NO_VSYNC_OPENGL_GLSL)" ""
|
ifeq "$(NO_VSYNC_OPENGL_GLSL)" ""
|
||||||
CFG += -DCONFIG_VSYNC_OPENGL_GLSL
|
CFG += -DCONFIG_VSYNC_OPENGL_GLSL
|
||||||
endif
|
endif
|
||||||
|
ifeq "$(NO_VSYNC_OPENGL_FBO)" ""
|
||||||
|
CFG += -DCONFIG_VSYNC_OPENGL_FBO
|
||||||
|
endif
|
||||||
|
ifeq "$(NO_VSYNC_OPENGL_VBO)" ""
|
||||||
|
CFG += -DCONFIG_VSYNC_OPENGL_VBO
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# ==== D-Bus ====
|
# ==== D-Bus ====
|
||||||
@ -73,7 +79,7 @@ CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\""
|
|||||||
|
|
||||||
LDFLAGS ?= -Wl,-O1 -Wl,--as-needed
|
LDFLAGS ?= -Wl,-O1 -Wl,--as-needed
|
||||||
|
|
||||||
ifeq "$(DEV)" ""
|
ifeq "$(CFG_DEV)" ""
|
||||||
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2
|
CFLAGS ?= -DNDEBUG -O2 -D_FORTIFY_SOURCE=2
|
||||||
else
|
else
|
||||||
CC = clang
|
CC = clang
|
||||||
|
@ -77,7 +77,7 @@ $ make install
|
|||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
* Our [FAQ](wiki/faq) covers some known issues.
|
* Our [FAQ](https://github.com/chjj/compton/wiki/vsync-guide) covers some known issues.
|
||||||
|
|
||||||
* VSync does not work too well. You may check the [VSync Guide](https://github.com/chjj/compton/wiki/vsync-guide) for how to get (possibly) better effects.
|
* VSync does not work too well. You may check the [VSync Guide](https://github.com/chjj/compton/wiki/vsync-guide) for how to get (possibly) better effects.
|
||||||
|
|
||||||
|
172
src/common.h
172
src/common.h
@ -26,6 +26,10 @@
|
|||||||
// #define DEBUG_FRAME 1
|
// #define DEBUG_FRAME 1
|
||||||
// #define DEBUG_LEADER 1
|
// #define DEBUG_LEADER 1
|
||||||
// #define DEBUG_C2 1
|
// #define DEBUG_C2 1
|
||||||
|
// #define DEBUG_GLX 1
|
||||||
|
// #define DEBUG_GLX_GLSL 1
|
||||||
|
// #define DEBUG_GLX_ERR 1
|
||||||
|
// #define DEBUG_GLX_MARK 1
|
||||||
// #define MONITOR_REPAINT 1
|
// #define MONITOR_REPAINT 1
|
||||||
|
|
||||||
// Whether to enable PCRE regular expression support in blacklists, enabled
|
// Whether to enable PCRE regular expression support in blacklists, enabled
|
||||||
@ -40,8 +44,12 @@
|
|||||||
// #define CONFIG_LIBCONFIG_LEGACY 1
|
// #define CONFIG_LIBCONFIG_LEGACY 1
|
||||||
// Whether to enable DRM VSync support
|
// Whether to enable DRM VSync support
|
||||||
// #define CONFIG_VSYNC_DRM 1
|
// #define CONFIG_VSYNC_DRM 1
|
||||||
// Whether to enable OpenGL VSync support
|
// Whether to enable OpenGL support
|
||||||
// #define CONFIG_VSYNC_OPENGL 1
|
// #define CONFIG_VSYNC_OPENGL 1
|
||||||
|
// Whether to enable GLX GLSL support
|
||||||
|
// #define CONFIG_VSYNC_OPENGL_GLSL 1
|
||||||
|
// Whether to enable GLX FBO support
|
||||||
|
// #define CONFIG_VSYNC_OPENGL_FBO 1
|
||||||
// Whether to enable DBus support with libdbus.
|
// Whether to enable DBus support with libdbus.
|
||||||
// #define CONFIG_DBUS 1
|
// #define CONFIG_DBUS 1
|
||||||
// Whether to enable condition support.
|
// Whether to enable condition support.
|
||||||
@ -96,7 +104,7 @@
|
|||||||
|
|
||||||
// libGL
|
// libGL
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#if defined(CONFIG_VSYNC_OPENGL_GLSL) || defined(CONFIG_VSYNC_OPENGL_FBO)
|
||||||
#define GL_GLEXT_PROTOTYPES
|
#define GL_GLEXT_PROTOTYPES
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -183,6 +191,9 @@
|
|||||||
/// @brief Maximum OpenGL buffer age.
|
/// @brief Maximum OpenGL buffer age.
|
||||||
#define CGLX_MAX_BUFFER_AGE 5
|
#define CGLX_MAX_BUFFER_AGE 5
|
||||||
|
|
||||||
|
/// @brief Maximum passes for blur.
|
||||||
|
#define MAX_BLUR_PASS 5
|
||||||
|
|
||||||
// Window flags
|
// Window flags
|
||||||
|
|
||||||
// Window size is changed
|
// Window size is changed
|
||||||
@ -343,6 +354,32 @@ struct _glx_texture {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
typedef struct {
|
||||||
|
/// Fragment shader for blur.
|
||||||
|
GLuint frag_shader;
|
||||||
|
/// GLSL program for blur.
|
||||||
|
GLuint prog;
|
||||||
|
/// Location of uniform "offset_x" in blur GLSL program.
|
||||||
|
GLint unifm_offset_x;
|
||||||
|
/// Location of uniform "offset_y" in blur GLSL program.
|
||||||
|
GLint unifm_offset_y;
|
||||||
|
/// Location of uniform "factor_center" in blur GLSL program.
|
||||||
|
GLint unifm_factor_center;
|
||||||
|
} glx_blur_pass_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/// Framebuffer used for blurring.
|
||||||
|
GLuint fbo;
|
||||||
|
/// Textures used for blurring.
|
||||||
|
GLuint textures[2];
|
||||||
|
/// Width of the textures.
|
||||||
|
int width;
|
||||||
|
/// Height of the textures.
|
||||||
|
int height;
|
||||||
|
} glx_blur_cache_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
Picture pict;
|
Picture pict;
|
||||||
@ -501,7 +538,7 @@ typedef struct {
|
|||||||
/// Background blur blacklist. A linked list of conditions.
|
/// Background blur blacklist. A linked list of conditions.
|
||||||
c2_lptr_t *blur_background_blacklist;
|
c2_lptr_t *blur_background_blacklist;
|
||||||
/// Blur convolution kernel.
|
/// Blur convolution kernel.
|
||||||
XFixed *blur_kern;
|
XFixed *blur_kerns[MAX_BLUR_PASS];
|
||||||
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
/// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
|
||||||
double inactive_dim;
|
double inactive_dim;
|
||||||
/// Whether to use fixed inactive dim opacity, instead of deciding
|
/// Whether to use fixed inactive dim opacity, instead of deciding
|
||||||
@ -614,6 +651,8 @@ typedef struct {
|
|||||||
/// Current GLX Z value.
|
/// Current GLX Z value.
|
||||||
int glx_z;
|
int glx_z;
|
||||||
#endif
|
#endif
|
||||||
|
// Cached blur convolution kernels.
|
||||||
|
XFixed *blur_kerns_cache[MAX_BLUR_PASS];
|
||||||
/// Reset program after next paint.
|
/// Reset program after next paint.
|
||||||
bool reset;
|
bool reset;
|
||||||
|
|
||||||
@ -702,16 +741,7 @@ typedef struct {
|
|||||||
/// 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
|
||||||
/// Fragment shader for blur.
|
glx_blur_pass_t glx_blur_passes[MAX_BLUR_PASS];
|
||||||
GLuint glx_frag_shader_blur;
|
|
||||||
/// GLSL program for blur.
|
|
||||||
GLuint glx_prog_blur;
|
|
||||||
/// Location of uniform "offset_x" in blur GLSL program.
|
|
||||||
GLint glx_prog_blur_unifm_offset_x;
|
|
||||||
/// Location of uniform "offset_y" in blur GLSL program.
|
|
||||||
GLint glx_prog_blur_unifm_offset_y;
|
|
||||||
/// Location of uniform "factor_center" in blur GLSL program.
|
|
||||||
GLint glx_prog_blur_unifm_factor_center;
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -908,6 +938,8 @@ typedef struct _win {
|
|||||||
/// Do not fade if it's false. Change on window type change.
|
/// Do not fade if it's false. Change on window type change.
|
||||||
/// Used by fading blacklist in the future.
|
/// Used by fading blacklist in the future.
|
||||||
bool fade;
|
bool fade;
|
||||||
|
/// Override value of window fade state. Set by D-Bus method calls.
|
||||||
|
switch_t fade_force;
|
||||||
/// Callback to be called after fading completed.
|
/// Callback to be called after fading completed.
|
||||||
void (*fade_callback) (session_t *ps, struct _win *w);
|
void (*fade_callback) (session_t *ps, struct _win *w);
|
||||||
|
|
||||||
@ -950,6 +982,11 @@ typedef struct _win {
|
|||||||
|
|
||||||
/// Whether to blur window background.
|
/// Whether to blur window background.
|
||||||
bool blur_background;
|
bool blur_background;
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
/// Textures and FBO background blur use.
|
||||||
|
glx_blur_cache_t glx_blur_cache;
|
||||||
|
#endif
|
||||||
} win;
|
} win;
|
||||||
|
|
||||||
/// Temporary structure used for communication between
|
/// Temporary structure used for communication between
|
||||||
@ -1749,6 +1786,9 @@ force_repaint(session_t *ps);
|
|||||||
bool
|
bool
|
||||||
vsync_init(session_t *ps);
|
vsync_init(session_t *ps);
|
||||||
|
|
||||||
|
void
|
||||||
|
vsync_deinit(session_t *ps);
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
/** @name GLX
|
/** @name GLX
|
||||||
*/
|
*/
|
||||||
@ -1788,9 +1828,13 @@ glx_tex_binded(const glx_texture_t *ptex, Pixmap pixmap) {
|
|||||||
void
|
void
|
||||||
glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg);
|
glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg);
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
bool
|
bool
|
||||||
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
GLfloat factor_center, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
|
GLfloat factor_center,
|
||||||
|
XserverRegion reg_tgt, const reg_data_t *pcache_reg,
|
||||||
|
glx_blur_cache_t *pbc);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
@ -1812,7 +1856,78 @@ glx_create_shader(GLenum shader_type, const char *shader_str);
|
|||||||
GLuint
|
GLuint
|
||||||
glx_create_program(const GLuint * const shaders, int nshaders);
|
glx_create_program(const GLuint * const shaders, int nshaders);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a GLX texture.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
free_texture_r(session_t *ps, GLuint *ptexture) {
|
||||||
|
if (*ptexture) {
|
||||||
|
assert(ps->glx_context);
|
||||||
|
glDeleteTextures(1, ptexture);
|
||||||
|
*ptexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a GLX Framebuffer object.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
free_glx_fbo(session_t *ps, GLuint *pfbo) {
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
if (*pfbo) {
|
||||||
|
glDeleteFramebuffers(1, pfbo);
|
||||||
|
*pfbo = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
assert(!*pfbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
/**
|
||||||
|
* Free data in glx_blur_cache_t on resize.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
|
||||||
|
free_texture_r(ps, &pbc->textures[0]);
|
||||||
|
free_texture_r(ps, &pbc->textures[1]);
|
||||||
|
pbc->width = 0;
|
||||||
|
pbc->height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a glx_blur_cache_t
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
|
||||||
|
free_glx_fbo(ps, &pbc->fbo);
|
||||||
|
free_glx_bc_resize(ps, pbc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a glx_texture_t.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
free_texture(session_t *ps, glx_texture_t **pptex) {
|
||||||
|
glx_texture_t *ptex = *pptex;
|
||||||
|
|
||||||
|
// Quit if there's nothing
|
||||||
|
if (!ptex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
|
glx_release_pixmap(ps, ptex);
|
||||||
|
|
||||||
|
free_texture_r(ps, &ptex->texture);
|
||||||
|
|
||||||
|
// Free structure itself
|
||||||
|
free(ptex);
|
||||||
|
*pptex = NULL;
|
||||||
|
#endif
|
||||||
|
assert(!*pptex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a OpenGL debugging marker.
|
* Add a OpenGL debugging marker.
|
||||||
@ -1846,29 +1961,6 @@ glx_mark_frame(session_t *ps) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
free_texture(session_t *ps, glx_texture_t **pptex) {
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
|
||||||
glx_texture_t *ptex = *pptex;
|
|
||||||
|
|
||||||
// Quit if there's nothing
|
|
||||||
if (!ptex)
|
|
||||||
return;
|
|
||||||
|
|
||||||
glx_release_pixmap(ps, ptex);
|
|
||||||
|
|
||||||
// Free texture
|
|
||||||
if (ptex->texture) {
|
|
||||||
glDeleteTextures(1, &ptex->texture);
|
|
||||||
ptex->texture = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free structure itself
|
|
||||||
free(ptex);
|
|
||||||
*pptex = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/** @name DBus handling
|
/** @name DBus handling
|
||||||
@ -1912,6 +2004,9 @@ cdbus_ev_win_focusin(session_t *ps, win *w);
|
|||||||
void
|
void
|
||||||
win_set_shadow_force(session_t *ps, win *w, switch_t val);
|
win_set_shadow_force(session_t *ps, win *w, switch_t val);
|
||||||
|
|
||||||
|
void
|
||||||
|
win_set_fade_force(session_t *ps, win *w, switch_t val);
|
||||||
|
|
||||||
void
|
void
|
||||||
win_set_focused_force(session_t *ps, win *w, switch_t val);
|
win_set_focused_force(session_t *ps, win *w, switch_t val);
|
||||||
|
|
||||||
@ -1920,6 +2015,9 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val);
|
|||||||
|
|
||||||
void
|
void
|
||||||
opts_init_track_focus(session_t *ps);
|
opts_init_track_focus(session_t *ps);
|
||||||
|
|
||||||
|
void
|
||||||
|
opts_set_no_fading_openclose(session_t *ps, bool newval);
|
||||||
//!@}
|
//!@}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
307
src/compton.c
307
src/compton.c
@ -70,6 +70,14 @@ static int (* const (VSYNC_FUNCS_WAIT[NUM_VSYNC]))(session_t *ps) = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Function pointers to deinitialize VSync.
|
||||||
|
static void (* const (VSYNC_FUNCS_DEINIT[NUM_VSYNC]))(session_t *ps) = {
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL
|
||||||
|
[VSYNC_OPENGL_SWC ] = vsync_opengl_swc_deinit,
|
||||||
|
[VSYNC_OPENGL_MSWC ] = vsync_opengl_mswc_deinit,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/// Names of root window properties that could point to a pixmap of
|
/// Names of root window properties that could point to a pixmap of
|
||||||
/// background.
|
/// background.
|
||||||
const static char *background_props_str[] = {
|
const static char *background_props_str[] = {
|
||||||
@ -1276,13 +1284,11 @@ win_paint_shadow(session_t *ps, win *w,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an alternative picture for a window.
|
* Create an picture.
|
||||||
*/
|
*/
|
||||||
static inline Picture
|
static inline Picture
|
||||||
win_build_picture(session_t *ps, win *w, XRenderPictFormat *pictfmt) {
|
xr_build_picture(session_t *ps, int wid, int hei,
|
||||||
const int wid = w->widthb;
|
XRenderPictFormat *pictfmt) {
|
||||||
const int hei = w->heightb;
|
|
||||||
|
|
||||||
if (!pictfmt)
|
if (!pictfmt)
|
||||||
pictfmt = XRenderFindVisualFormat(ps->dpy, ps->vis);
|
pictfmt = XRenderFindVisualFormat(ps->dpy, ps->vis);
|
||||||
|
|
||||||
@ -1299,6 +1305,73 @@ win_build_picture(session_t *ps, win *w, XRenderPictFormat *pictfmt) {
|
|||||||
return tmp_picture;
|
return tmp_picture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Blur an area on a buffer.
|
||||||
|
*
|
||||||
|
* @param ps current session
|
||||||
|
* @param tgt_buffer a buffer as both source and destination
|
||||||
|
* @param x x pos
|
||||||
|
* @param y y pos
|
||||||
|
* @param wid width
|
||||||
|
* @param hei height
|
||||||
|
* @param blur_kerns blur kernels, ending with a NULL, guaranteed to have at
|
||||||
|
* least one kernel
|
||||||
|
* @param reg_clip a clipping region to be applied on intermediate buffers
|
||||||
|
*
|
||||||
|
* @return true if successful, false otherwise
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
xr_blur_dst(session_t *ps, Picture tgt_buffer,
|
||||||
|
int x, int y, int wid, int hei, XFixed **blur_kerns,
|
||||||
|
XserverRegion reg_clip) {
|
||||||
|
assert(blur_kerns[0]);
|
||||||
|
|
||||||
|
// Directly copying from tgt_buffer to it does not work, so we create a
|
||||||
|
// Picture in the middle.
|
||||||
|
Picture tmp_picture = xr_build_picture(ps, wid, hei, NULL);
|
||||||
|
|
||||||
|
if (!tmp_picture) {
|
||||||
|
printf_errf("(): Failed to build intermediate Picture.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_clip && tmp_picture)
|
||||||
|
XFixesSetPictureClipRegion(ps->dpy, tmp_picture, reg_clip, 0, 0);
|
||||||
|
|
||||||
|
Picture src_pict = tgt_buffer, dst_pict = tmp_picture;
|
||||||
|
for (int i = 0; blur_kerns[i]; ++i) {
|
||||||
|
assert(i < MAX_BLUR_PASS - 1);
|
||||||
|
XFixed *convolution_blur = blur_kerns[i];
|
||||||
|
int kwid = XFixedToDouble(convolution_blur[0]),
|
||||||
|
khei = XFixedToDouble(convolution_blur[1]);
|
||||||
|
bool rd_from_tgt = (tgt_buffer == src_pict);
|
||||||
|
|
||||||
|
// Copy from source picture to destination. The filter must
|
||||||
|
// be applied on source picture, to get the nearby pixels outside the
|
||||||
|
// window.
|
||||||
|
XRenderSetPictureFilter(ps->dpy, src_pict, XRFILTER_CONVOLUTION,
|
||||||
|
convolution_blur, kwid * khei + 2);
|
||||||
|
XRenderComposite(ps->dpy, PictOpSrc, src_pict, None, dst_pict,
|
||||||
|
(rd_from_tgt ? x: 0), (rd_from_tgt ? y: 0), 0, 0,
|
||||||
|
(rd_from_tgt ? 0: x), (rd_from_tgt ? 0: y), wid, hei);
|
||||||
|
xrfilter_reset(ps, src_pict);
|
||||||
|
|
||||||
|
{
|
||||||
|
XserverRegion tmp = src_pict;
|
||||||
|
src_pict = dst_pict;
|
||||||
|
dst_pict = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_pict != tgt_buffer)
|
||||||
|
XRenderComposite(ps->dpy, PictOpSrc, src_pict, None, tgt_buffer,
|
||||||
|
0, 0, 0, 0, x, y, wid, hei);
|
||||||
|
|
||||||
|
free_picture(ps, &tmp_picture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blur the background of a window.
|
* Blur the background of a window.
|
||||||
*/
|
*/
|
||||||
@ -1321,46 +1394,63 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
|
|||||||
switch (ps->o.backend) {
|
switch (ps->o.backend) {
|
||||||
case BKEND_XRENDER:
|
case BKEND_XRENDER:
|
||||||
{
|
{
|
||||||
// Directly copying from tgt_buffer does not work, so we create a
|
// Normalize blur kernels
|
||||||
// Picture in the middle.
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
Picture tmp_picture = win_build_picture(ps, w, NULL);
|
XFixed *kern_src = ps->o.blur_kerns[i];
|
||||||
|
XFixed *kern_dst = ps->blur_kerns_cache[i];
|
||||||
|
assert(i < MAX_BLUR_PASS);
|
||||||
|
if (!kern_src) {
|
||||||
|
assert(!kern_dst);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tmp_picture)
|
assert(!kern_dst
|
||||||
|
|| (kern_src[0] == kern_dst[0] && kern_src[1] == kern_dst[1]));
|
||||||
|
|
||||||
|
// Skip for fixed factor_center if the cache exists already
|
||||||
|
if (ps->o.blur_background_fixed && kern_dst) continue;
|
||||||
|
|
||||||
|
int kwid = XFixedToDouble(kern_src[0]),
|
||||||
|
khei = XFixedToDouble(kern_src[1]);
|
||||||
|
|
||||||
|
// Allocate cache space if needed
|
||||||
|
if (!kern_dst) {
|
||||||
|
kern_dst = malloc((kwid * khei + 2) * sizeof(XFixed));
|
||||||
|
if (!kern_dst) {
|
||||||
|
printf_errf("(): Failed to allocate memory for blur kernel.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
XFixed *convolution_blur = ps->o.blur_kern;
|
ps->blur_kerns_cache[i] = kern_dst;
|
||||||
int kwid = XFixedToDouble((ps->o.blur_kern[0])),
|
}
|
||||||
khei = XFixedToDouble((ps->o.blur_kern[1]));
|
|
||||||
|
|
||||||
// Modify the factor of the center pixel
|
// Modify the factor of the center pixel
|
||||||
convolution_blur[2 + (khei / 2) * kwid + kwid / 2] = XDoubleToFixed(factor_center);
|
kern_src[2 + (khei / 2) * kwid + kwid / 2] =
|
||||||
|
XDoubleToFixed(factor_center);
|
||||||
|
|
||||||
|
// Copy over
|
||||||
|
memcpy(kern_dst, kern_src, (kwid * khei + 2) * sizeof(XFixed));
|
||||||
|
normalize_conv_kern(kwid, khei, kern_dst + 2);
|
||||||
|
}
|
||||||
|
|
||||||
// Minimize the region we try to blur, if the window itself is not
|
// Minimize the region we try to blur, if the window itself is not
|
||||||
// opaque, only the frame is.
|
// opaque, only the frame is.
|
||||||
if (WMODE_SOLID == w->mode && w->frame_opacity) {
|
XserverRegion reg_noframe = None;
|
||||||
|
if (WMODE_SOLID == w->mode) {
|
||||||
XserverRegion reg_all = border_size(ps, w, false);
|
XserverRegion reg_all = border_size(ps, w, false);
|
||||||
XserverRegion reg_noframe = win_get_region_noframe(ps, w, false);
|
reg_noframe = win_get_region_noframe(ps, w, false);
|
||||||
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
|
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
|
||||||
XFixesSetPictureClipRegion(ps->dpy, tmp_picture, reg_noframe, 0, 0);
|
|
||||||
free_region(ps, ®_all);
|
free_region(ps, ®_all);
|
||||||
|
}
|
||||||
|
xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache,
|
||||||
|
reg_noframe);
|
||||||
free_region(ps, ®_noframe);
|
free_region(ps, ®_noframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the content to tmp_picture, then copy back. The filter must
|
|
||||||
// be applied on tgt_buffer, to get the nearby pixels outside the
|
|
||||||
// window.
|
|
||||||
XRenderSetPictureFilter(ps->dpy, tgt_buffer, XRFILTER_CONVOLUTION, convolution_blur, kwid * khei + 2);
|
|
||||||
XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None, tmp_picture, x, y, 0, 0, 0, 0, wid, hei);
|
|
||||||
xrfilter_reset(ps, tgt_buffer);
|
|
||||||
XRenderComposite(ps->dpy, PictOpSrc, tmp_picture, None, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
|
|
||||||
|
|
||||||
free_picture(ps, &tmp_picture);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_VSYNC_OPENGL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
case BKEND_GLX:
|
case BKEND_GLX:
|
||||||
|
// TODO: Handle frame opacity
|
||||||
glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center,
|
glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center,
|
||||||
reg_paint, pcache_reg);
|
reg_paint, pcache_reg, &w->glx_blur_cache);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -1447,7 +1537,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
|
|||||||
|
|
||||||
// Invert window color, if required
|
// Invert window color, if required
|
||||||
if (BKEND_XRENDER == ps->o.backend && w->invert_color) {
|
if (BKEND_XRENDER == ps->o.backend && w->invert_color) {
|
||||||
Picture newpict = win_build_picture(ps, w, w->pictfmt);
|
Picture newpict = xr_build_picture(ps, wid, hei, w->pictfmt);
|
||||||
if (newpict) {
|
if (newpict) {
|
||||||
// Apply clipping region to save some CPU
|
// Apply clipping region to save some CPU
|
||||||
if (reg_paint) {
|
if (reg_paint) {
|
||||||
@ -1993,14 +2083,8 @@ map_win(session_t *ps, Window id) {
|
|||||||
win_determine_shadow(ps, w);
|
win_determine_shadow(ps, w);
|
||||||
|
|
||||||
// Set fading state
|
// Set fading state
|
||||||
w->in_openclose = false;
|
|
||||||
if (ps->o.no_fading_openclose) {
|
|
||||||
set_fade_callback(ps, w, finish_map_win, true);
|
|
||||||
w->in_openclose = true;
|
w->in_openclose = true;
|
||||||
}
|
set_fade_callback(ps, w, finish_map_win, true);
|
||||||
else {
|
|
||||||
set_fade_callback(ps, w, NULL, true);
|
|
||||||
}
|
|
||||||
win_determine_fade(ps, w);
|
win_determine_fade(ps, w);
|
||||||
|
|
||||||
win_determine_blur_background(ps, w);
|
win_determine_blur_background(ps, w);
|
||||||
@ -2066,9 +2150,7 @@ unmap_win(session_t *ps, win *w) {
|
|||||||
// Fading out
|
// Fading out
|
||||||
w->flags |= WFLAG_OPCT_CHANGE;
|
w->flags |= WFLAG_OPCT_CHANGE;
|
||||||
set_fade_callback(ps, w, unmap_callback, false);
|
set_fade_callback(ps, w, unmap_callback, false);
|
||||||
if (ps->o.no_fading_openclose) {
|
|
||||||
w->in_openclose = true;
|
w->in_openclose = true;
|
||||||
}
|
|
||||||
win_determine_fade(ps, w);
|
win_determine_fade(ps, w);
|
||||||
|
|
||||||
// Validate pixmap if we have to do fading
|
// Validate pixmap if we have to do fading
|
||||||
@ -2195,7 +2277,9 @@ calc_dim(session_t *ps, win *w) {
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
win_determine_fade(session_t *ps, win *w) {
|
win_determine_fade(session_t *ps, win *w) {
|
||||||
if ((ps->o.no_fading_openclose && w->in_openclose)
|
if (UNSET != w->fade_force)
|
||||||
|
w->fade = w->fade_force;
|
||||||
|
else if ((ps->o.no_fading_openclose && w->in_openclose)
|
||||||
|| win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst))
|
|| win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst))
|
||||||
w->fade = false;
|
w->fade = false;
|
||||||
else
|
else
|
||||||
@ -2593,6 +2677,7 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||||||
.opacity_prop_client = OPAQUE,
|
.opacity_prop_client = OPAQUE,
|
||||||
|
|
||||||
.fade = false,
|
.fade = false,
|
||||||
|
.fade_force = UNSET,
|
||||||
.fade_callback = NULL,
|
.fade_callback = NULL,
|
||||||
|
|
||||||
.frame_opacity = 0.0,
|
.frame_opacity = 0.0,
|
||||||
@ -3418,6 +3503,19 @@ win_set_shadow_force(session_t *ps, win *w, switch_t val) {
|
|||||||
if (val != w->shadow_force) {
|
if (val != w->shadow_force) {
|
||||||
w->shadow_force = val;
|
w->shadow_force = val;
|
||||||
win_determine_shadow(ps, w);
|
win_determine_shadow(ps, w);
|
||||||
|
ps->ev_received = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set w->fade_force of a window.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
win_set_fade_force(session_t *ps, win *w, switch_t val) {
|
||||||
|
if (val != w->fade_force) {
|
||||||
|
w->fade_force = val;
|
||||||
|
win_determine_fade(ps, w);
|
||||||
|
ps->ev_received = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3429,6 +3527,7 @@ win_set_focused_force(session_t *ps, win *w, switch_t val) {
|
|||||||
if (val != w->focused_force) {
|
if (val != w->focused_force) {
|
||||||
w->focused_force = val;
|
w->focused_force = val;
|
||||||
win_update_focused(ps, w);
|
win_update_focused(ps, w);
|
||||||
|
ps->ev_received = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3440,6 +3539,7 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
|
|||||||
if (val != w->invert_color_force) {
|
if (val != w->invert_color_force) {
|
||||||
w->invert_color_force = val;
|
w->invert_color_force = val;
|
||||||
win_determine_invert_color(ps, w);
|
win_determine_invert_color(ps, w);
|
||||||
|
ps->ev_received = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3465,6 +3565,20 @@ opts_init_track_focus(session_t *ps) {
|
|||||||
// Recheck focus
|
// Recheck focus
|
||||||
recheck_focus(ps);
|
recheck_focus(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set no_fading_openclose option.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
opts_set_no_fading_openclose(session_t *ps, bool newval) {
|
||||||
|
if (newval != ps->o.no_fading_openclose) {
|
||||||
|
ps->o.no_fading_openclose = newval;
|
||||||
|
for (win *w = ps->list; w; w = w->next)
|
||||||
|
win_determine_fade(ps, w);
|
||||||
|
ps->ev_received = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//!@}
|
//!@}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -4222,6 +4336,8 @@ usage(int ret) {
|
|||||||
" --blur-background-fixed.\n"
|
" --blur-background-fixed.\n"
|
||||||
" A 7x7 Guassian blur kernel looks like:\n"
|
" A 7x7 Guassian blur kernel looks like:\n"
|
||||||
" --blur-kern '7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003'\n"
|
" --blur-kern '7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003'\n"
|
||||||
|
" Up to 4 blur kernels may be specified, separated with semicolon, for\n"
|
||||||
|
" multi-pass blur.\n"
|
||||||
" May also be one the predefined kernels: 3x3box (default), 5x5box,\n"
|
" May also be one the predefined kernels: 3x3box (default), 5x5box,\n"
|
||||||
" 7x7box, 3x3gaussian, 5x5gaussian, 7x7gaussian, 9x9gaussian,\n"
|
" 7x7box, 3x3gaussian, 5x5gaussian, 7x7gaussian, 9x9gaussian,\n"
|
||||||
" 11x11gaussian.\n"
|
" 11x11gaussian.\n"
|
||||||
@ -4419,7 +4535,7 @@ parse_matrix_readnum(const char *src, double *dest) {
|
|||||||
* Parse a matrix.
|
* Parse a matrix.
|
||||||
*/
|
*/
|
||||||
static inline XFixed *
|
static inline XFixed *
|
||||||
parse_matrix(session_t *ps, const char *src) {
|
parse_matrix(session_t *ps, const char *src, const char **endptr) {
|
||||||
int wid = 0, hei = 0;
|
int wid = 0, hei = 0;
|
||||||
const char *pc = NULL;
|
const char *pc = NULL;
|
||||||
XFixed *matrix = NULL;
|
XFixed *matrix = NULL;
|
||||||
@ -4481,12 +4597,28 @@ parse_matrix(session_t *ps, const char *src) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Detect trailing characters
|
// Detect trailing characters
|
||||||
for ( ;*pc; ++pc)
|
for ( ;*pc && ';' != *pc; ++pc)
|
||||||
if (!isspace(*pc) && ',' != *pc) {
|
if (!isspace(*pc) && ',' != *pc) {
|
||||||
printf_errf("(): Trailing characters in matrix string.");
|
printf_errf("(): Trailing characters in matrix string.");
|
||||||
goto parse_matrix_err;
|
goto parse_matrix_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jump over spaces after ';'
|
||||||
|
if (';' == *pc) {
|
||||||
|
++pc;
|
||||||
|
while (*pc && isspace(*pc))
|
||||||
|
++pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Require an end of string if endptr is not provided, otherwise
|
||||||
|
// copy end pointer to endptr
|
||||||
|
if (endptr)
|
||||||
|
*endptr = pc;
|
||||||
|
else if (*pc) {
|
||||||
|
printf_errf("(): Only one matrix expected.");
|
||||||
|
goto parse_matrix_err;
|
||||||
|
}
|
||||||
|
|
||||||
// Fill in width and height
|
// Fill in width and height
|
||||||
matrix[0] = XDoubleToFixed(wid);
|
matrix[0] = XDoubleToFixed(wid);
|
||||||
matrix[1] = XDoubleToFixed(hei);
|
matrix[1] = XDoubleToFixed(hei);
|
||||||
@ -4502,7 +4634,12 @@ parse_matrix_err:
|
|||||||
* Parse a convolution kernel.
|
* Parse a convolution kernel.
|
||||||
*/
|
*/
|
||||||
static inline XFixed *
|
static inline XFixed *
|
||||||
parse_conv_kern(session_t *ps, const char *src) {
|
parse_conv_kern(session_t *ps, const char *src, const char **endptr) {
|
||||||
|
return parse_matrix(ps, src, endptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) {
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *kern_str;
|
const char *kern_str;
|
||||||
@ -4519,8 +4656,30 @@ parse_conv_kern(session_t *ps, const char *src) {
|
|||||||
for (int i = 0;
|
for (int i = 0;
|
||||||
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i)
|
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i)
|
||||||
if (!strcmp(CONV_KERN_PREDEF[i].name, src))
|
if (!strcmp(CONV_KERN_PREDEF[i].name, src))
|
||||||
return parse_matrix(ps, CONV_KERN_PREDEF[i].kern_str);
|
return parse_conv_kern_lst(ps, CONV_KERN_PREDEF[i].kern_str, dest, max);
|
||||||
return parse_matrix(ps, src);
|
|
||||||
|
int i = 0;
|
||||||
|
const char *pc = src;
|
||||||
|
|
||||||
|
// Free old kernels
|
||||||
|
for (i = 0; i < max; ++i) {
|
||||||
|
free(dest[i]);
|
||||||
|
dest[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue parsing until the end of source string
|
||||||
|
i = 0;
|
||||||
|
while (pc && *pc && i < max - 1) {
|
||||||
|
if (!(dest[i++] = parse_conv_kern(ps, pc, &pc)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pc) {
|
||||||
|
printf_errf("(): Too many blur kernels!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LIBCONFIG
|
#ifdef CONFIG_LIBCONFIG
|
||||||
@ -5115,9 +5274,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
|||||||
break;
|
break;
|
||||||
case 301:
|
case 301:
|
||||||
// --blur-kern
|
// --blur-kern
|
||||||
free(ps->o.blur_kern);
|
if (!parse_conv_kern_lst(ps, optarg, ps->o.blur_kerns, MAX_BLUR_PASS))
|
||||||
if (!(ps->o.blur_kern = parse_conv_kern(ps, optarg)))
|
|
||||||
exit(1);
|
exit(1);
|
||||||
|
break;
|
||||||
case 302:
|
case 302:
|
||||||
// --resize-damage
|
// --resize-damage
|
||||||
ps->o.resize_damage = atoi(optarg);
|
ps->o.resize_damage = atoi(optarg);
|
||||||
@ -5187,7 +5346,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fill default blur kernel
|
// Fill default blur kernel
|
||||||
if (ps->o.blur_background && !ps->o.blur_kern) {
|
if (ps->o.blur_background && !ps->o.blur_kerns[0]) {
|
||||||
// Convolution filter parameter (box blur)
|
// Convolution filter parameter (box blur)
|
||||||
// gaussian or binomial filters are definitely superior, yet looks
|
// gaussian or binomial filters are definitely superior, yet looks
|
||||||
// like they aren't supported as of xorg-server-1.13.0
|
// like they aren't supported as of xorg-server-1.13.0
|
||||||
@ -5200,12 +5359,12 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
|
|||||||
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
||||||
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1),
|
||||||
};
|
};
|
||||||
ps->o.blur_kern = malloc(sizeof(convolution_blur));
|
ps->o.blur_kerns[0] = malloc(sizeof(convolution_blur));
|
||||||
if (!ps->o.blur_kern) {
|
if (!ps->o.blur_kerns[0]) {
|
||||||
printf_errf("(): Failed to allocate memory for convolution kernel.");
|
printf_errf("(): Failed to allocate memory for convolution kernel.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memcpy(ps->o.blur_kern, &convolution_blur, sizeof(convolution_blur));
|
memcpy(ps->o.blur_kerns[0], &convolution_blur, sizeof(convolution_blur));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5536,6 +5695,19 @@ vsync_opengl_oml_wait(session_t *ps) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vsync_opengl_swc_deinit(session_t *ps) {
|
||||||
|
// The standard says it doesn't accept 0, but in fact it probably does
|
||||||
|
if (ps->glx_context && ps->glXSwapIntervalProc)
|
||||||
|
ps->glXSwapIntervalProc(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vsync_opengl_mswc_deinit(session_t *ps) {
|
||||||
|
if (ps->glx_context && ps->glXSwapIntervalMESAProc)
|
||||||
|
ps->glXSwapIntervalMESAProc(0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5564,6 +5736,16 @@ vsync_wait(session_t *ps) {
|
|||||||
VSYNC_FUNCS_WAIT[ps->o.vsync](ps);
|
VSYNC_FUNCS_WAIT[ps->o.vsync](ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deinitialize current VSync method.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vsync_deinit(session_t *ps) {
|
||||||
|
if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync])
|
||||||
|
VSYNC_FUNCS_DEINIT[ps->o.vsync](ps);
|
||||||
|
ps->o.vsync = VSYNC_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pregenerate alpha pictures.
|
* Pregenerate alpha pictures.
|
||||||
*/
|
*/
|
||||||
@ -6030,7 +6212,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
.blur_background_frame = false,
|
.blur_background_frame = false,
|
||||||
.blur_background_fixed = false,
|
.blur_background_fixed = false,
|
||||||
.blur_background_blacklist = NULL,
|
.blur_background_blacklist = NULL,
|
||||||
.blur_kern = NULL,
|
.blur_kerns = { NULL },
|
||||||
.inactive_dim = 0.0,
|
.inactive_dim = 0.0,
|
||||||
.inactive_dim_fixed = false,
|
.inactive_dim_fixed = false,
|
||||||
.invert_color_list = NULL,
|
.invert_color_list = NULL,
|
||||||
@ -6096,12 +6278,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
.glXWaitVideoSyncSGI = NULL,
|
.glXWaitVideoSyncSGI = NULL,
|
||||||
.glXGetSyncValuesOML = NULL,
|
.glXGetSyncValuesOML = NULL,
|
||||||
.glXWaitForMscOML = NULL,
|
.glXWaitForMscOML = NULL,
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
|
||||||
.glx_prog_blur_unifm_offset_x = -1,
|
|
||||||
.glx_prog_blur_unifm_offset_y = -1,
|
|
||||||
.glx_prog_blur_unifm_factor_center = -1,
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.xfixes_event = 0,
|
.xfixes_event = 0,
|
||||||
@ -6151,6 +6327,14 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||||||
// Allocate a session and copy default values into it
|
// Allocate a session and copy default values into it
|
||||||
session_t *ps = malloc(sizeof(session_t));
|
session_t *ps = malloc(sizeof(session_t));
|
||||||
memcpy(ps, &s_def, sizeof(session_t));
|
memcpy(ps, &s_def, sizeof(session_t));
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
|
||||||
|
ppass->unifm_factor_center = -1;
|
||||||
|
ppass->unifm_offset_x = -1;
|
||||||
|
ppass->unifm_offset_y = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ps_g = ps;
|
ps_g = ps;
|
||||||
ps->ignore_tail = &ps->ignore_head;
|
ps->ignore_tail = &ps->ignore_head;
|
||||||
gettimeofday(&ps->time_start, NULL);
|
gettimeofday(&ps->time_start, NULL);
|
||||||
@ -6513,7 +6697,10 @@ session_destroy(session_t *ps) {
|
|||||||
free(ps->o.display);
|
free(ps->o.display);
|
||||||
free(ps->o.logpath);
|
free(ps->o.logpath);
|
||||||
free(ps->o.config_file);
|
free(ps->o.config_file);
|
||||||
free(ps->o.blur_kern);
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
free(ps->o.blur_kerns[i]);
|
||||||
|
free(ps->blur_kerns_cache[i]);
|
||||||
|
}
|
||||||
free(ps->pfds_read);
|
free(ps->pfds_read);
|
||||||
free(ps->pfds_write);
|
free(ps->pfds_write);
|
||||||
free(ps->pfds_except);
|
free(ps->pfds_except);
|
||||||
|
@ -231,6 +231,9 @@ free_win_res(session_t *ps, win *w) {
|
|||||||
free(w->class_instance);
|
free(w->class_instance);
|
||||||
free(w->class_general);
|
free(w->class_general);
|
||||||
free(w->role);
|
free(w->role);
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
free_glx_bc(ps, &w->glx_blur_cache);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -594,6 +597,24 @@ set_tgt_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
xr_blur_dst(session_t *ps, Picture tgt_buffer,
|
||||||
|
int x, int y, int wid, int hei, XFixed **blur_kerns,
|
||||||
|
XserverRegion reg_clip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a convolution kernel.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
normalize_conv_kern(int wid, int hei, XFixed *kern) {
|
||||||
|
double sum = 0.0;
|
||||||
|
for (int i = 0; i < wid * hei; ++i)
|
||||||
|
sum += XFixedToDouble(kern[i]);
|
||||||
|
double factor = 1.0 / sum;
|
||||||
|
for (int i = 0; i < wid * hei; ++i)
|
||||||
|
kern[i] = XDoubleToFixed(XFixedToDouble(kern[i]) * factor);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t);
|
paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t);
|
||||||
|
|
||||||
@ -1095,6 +1116,12 @@ vsync_opengl_wait(session_t *ps);
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
vsync_opengl_oml_wait(session_t *ps);
|
vsync_opengl_oml_wait(session_t *ps);
|
||||||
|
|
||||||
|
static void
|
||||||
|
vsync_opengl_swc_deinit(session_t *ps);
|
||||||
|
|
||||||
|
static void
|
||||||
|
vsync_opengl_mswc_deinit(session_t *ps);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
53
src/dbus.c
53
src/dbus.c
@ -717,6 +717,7 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
|
|||||||
cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
|
cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
|
||||||
cdbus_m_win_get_do(leader, cdbus_reply_wid);
|
cdbus_m_win_get_do(leader, cdbus_reply_wid);
|
||||||
cdbus_m_win_get_do(focused_real, cdbus_reply_bool);
|
cdbus_m_win_get_do(focused_real, cdbus_reply_bool);
|
||||||
|
cdbus_m_win_get_do(fade_force, cdbus_reply_enum);
|
||||||
cdbus_m_win_get_do(shadow_force, cdbus_reply_enum);
|
cdbus_m_win_get_do(shadow_force, cdbus_reply_enum);
|
||||||
cdbus_m_win_get_do(focused_force, cdbus_reply_enum);
|
cdbus_m_win_get_do(focused_force, cdbus_reply_enum);
|
||||||
cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
|
cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
|
||||||
@ -770,8 +771,6 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->ev_received = true;
|
|
||||||
|
|
||||||
#define cdbus_m_win_set_do(tgt, type, real_type) \
|
#define cdbus_m_win_set_do(tgt, type, real_type) \
|
||||||
if (!strcmp(MSTR(tgt), target)) { \
|
if (!strcmp(MSTR(tgt), target)) { \
|
||||||
real_type val; \
|
real_type val; \
|
||||||
@ -789,6 +788,14 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
|
|||||||
goto cdbus_process_win_set_success;
|
goto cdbus_process_win_set_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp("fade_force", target)) {
|
||||||
|
cdbus_enum_t val = UNSET;
|
||||||
|
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
||||||
|
return false;
|
||||||
|
win_set_fade_force(ps, w, val);
|
||||||
|
goto cdbus_process_win_set_success;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp("focused_force", target)) {
|
if (!strcmp("focused_force", target)) {
|
||||||
cdbus_enum_t val = UNSET;
|
cdbus_enum_t val = UNSET;
|
||||||
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
||||||
@ -912,6 +919,11 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
|||||||
cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
|
cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
|
||||||
cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
|
cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
|
||||||
|
|
||||||
|
cdbus_m_opts_get_do(fade_delta, cdbus_reply_int32);
|
||||||
|
cdbus_m_opts_get_do(fade_in_step, cdbus_reply_int32);
|
||||||
|
cdbus_m_opts_get_do(fade_out_step, cdbus_reply_int32);
|
||||||
|
cdbus_m_opts_get_do(no_fading_openclose, cdbus_reply_bool);
|
||||||
|
|
||||||
cdbus_m_opts_get_do(blur_background, cdbus_reply_bool);
|
cdbus_m_opts_get_do(blur_background, cdbus_reply_bool);
|
||||||
cdbus_m_opts_get_do(blur_background_frame, cdbus_reply_bool);
|
cdbus_m_opts_get_do(blur_background_frame, cdbus_reply_bool);
|
||||||
cdbus_m_opts_get_do(blur_background_fixed, cdbus_reply_bool);
|
cdbus_m_opts_get_do(blur_background_fixed, cdbus_reply_bool);
|
||||||
@ -961,6 +973,42 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
|||||||
goto cdbus_process_opts_set_success; \
|
goto cdbus_process_opts_set_success; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fade_delta
|
||||||
|
if (!strcmp("fade_delta", target)) {
|
||||||
|
int32_t val = 0.0;
|
||||||
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_INT32, &val))
|
||||||
|
return false;
|
||||||
|
ps->o.fade_delta = max_i(val, 1);
|
||||||
|
goto cdbus_process_opts_set_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fade_in_step
|
||||||
|
if (!strcmp("fade_in_step", target)) {
|
||||||
|
double val = 0.0;
|
||||||
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
||||||
|
return false;
|
||||||
|
ps->o.fade_in_step = normalize_d(val) * OPAQUE;
|
||||||
|
goto cdbus_process_opts_set_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fade_out_step
|
||||||
|
if (!strcmp("fade_out_step", target)) {
|
||||||
|
double val = 0.0;
|
||||||
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
||||||
|
return false;
|
||||||
|
ps->o.fade_out_step = normalize_d(val) * OPAQUE;
|
||||||
|
goto cdbus_process_opts_set_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no_fading_openclose
|
||||||
|
if (!strcmp("no_fading_openclose", target)) {
|
||||||
|
dbus_bool_t val = FALSE;
|
||||||
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
|
||||||
|
return false;
|
||||||
|
opts_set_no_fading_openclose(ps, val);
|
||||||
|
goto cdbus_process_opts_set_success;
|
||||||
|
}
|
||||||
|
|
||||||
// unredir_if_possible
|
// unredir_if_possible
|
||||||
if (!strcmp("unredir_if_possible", target)) {
|
if (!strcmp("unredir_if_possible", target)) {
|
||||||
dbus_bool_t val = FALSE;
|
dbus_bool_t val = FALSE;
|
||||||
@ -1002,6 +1050,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
|||||||
const char * val = NULL;
|
const char * val = NULL;
|
||||||
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_STRING, &val))
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_STRING, &val))
|
||||||
return false;
|
return false;
|
||||||
|
vsync_deinit(ps);
|
||||||
if (!parse_vsync(ps, val)) {
|
if (!parse_vsync(ps, val)) {
|
||||||
printf_errf("(): " CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
|
printf_errf("(): " CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
|
||||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADARG, CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADARG, CDBUS_ERROR_BADARG_S, 1, "Value invalid.");
|
||||||
|
322
src/opengl.c
322
src/opengl.c
@ -160,10 +160,13 @@ void
|
|||||||
glx_destroy(session_t *ps) {
|
glx_destroy(session_t *ps) {
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
// Free GLSL shaders/programs
|
// Free GLSL shaders/programs
|
||||||
if (ps->glx_frag_shader_blur)
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
glDeleteShader(ps->glx_frag_shader_blur);
|
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
|
||||||
if (ps->glx_prog_blur)
|
if (ppass->frag_shader)
|
||||||
glDeleteProgram(ps->glx_prog_blur);
|
glDeleteShader(ppass->frag_shader);
|
||||||
|
if (ppass->prog)
|
||||||
|
glDeleteProgram(ppass->prog);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free FBConfigs
|
// Free FBConfigs
|
||||||
@ -199,8 +202,28 @@ glx_on_root_change(session_t *ps) {
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
glx_init_blur(session_t *ps) {
|
glx_init_blur(session_t *ps) {
|
||||||
|
assert(ps->o.blur_kerns[0]);
|
||||||
|
|
||||||
|
// Allocate PBO if more than one blur kernel is present
|
||||||
|
if (ps->o.blur_kerns[1]) {
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
// Try to generate a framebuffer
|
||||||
|
GLuint fbo = 0;
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
if (!fbo) {
|
||||||
|
printf_errf("(): Failed to generate Framebuffer. Cannot do "
|
||||||
|
"multi-pass blur with GLX backend.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
#else
|
||||||
|
printf_errf("(): FBO support not compiled in. Cannot do multi-pass blur "
|
||||||
|
"with GLX backend.");
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
// Build shader
|
|
||||||
{
|
{
|
||||||
static const char *FRAG_SHADER_BLUR_PREFIX =
|
static const char *FRAG_SHADER_BLUR_PREFIX =
|
||||||
"#version 110\n"
|
"#version 110\n"
|
||||||
@ -235,8 +258,16 @@ glx_init_blur(session_t *ps) {
|
|||||||
shader_add = FRAG_SHADER_BLUR_ADD_GPUSHADER4;
|
shader_add = FRAG_SHADER_BLUR_ADD_GPUSHADER4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wid = XFixedToDouble(ps->o.blur_kern[0]),
|
for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) {
|
||||||
hei = XFixedToDouble(ps->o.blur_kern[1]);
|
XFixed *kern = ps->o.blur_kerns[i];
|
||||||
|
if (!kern)
|
||||||
|
break;
|
||||||
|
|
||||||
|
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
|
||||||
|
|
||||||
|
// Build shader
|
||||||
|
{
|
||||||
|
int wid = XFixedToDouble(kern[0]), hei = XFixedToDouble(kern[1]);
|
||||||
int nele = wid * hei - 1;
|
int nele = wid * hei - 1;
|
||||||
int len = strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) + strlen(extension) + (strlen(shader_add) + strlen(texture_func) + 42) * nele + strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1;
|
int len = strlen(FRAG_SHADER_BLUR_PREFIX) + strlen(sampler_type) + strlen(extension) + (strlen(shader_add) + strlen(texture_func) + 42) * nele + strlen(FRAG_SHADER_BLUR_SUFFIX) + strlen(texture_func) + 12 + 1;
|
||||||
char *shader_str = calloc(len, sizeof(char));
|
char *shader_str = calloc(len, sizeof(char));
|
||||||
@ -251,15 +282,15 @@ glx_init_blur(session_t *ps) {
|
|||||||
assert(strlen(shader_str) < len);
|
assert(strlen(shader_str) < len);
|
||||||
|
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for (int i = 0; i < hei; ++i) {
|
for (int j = 0; j < hei; ++j) {
|
||||||
for (int j = 0; j < wid; ++j) {
|
for (int k = 0; k < wid; ++k) {
|
||||||
if (hei / 2 == i && wid / 2 == j)
|
if (hei / 2 == j && wid / 2 == k)
|
||||||
continue;
|
continue;
|
||||||
double val = XFixedToDouble(ps->o.blur_kern[2 + i * wid + j]);
|
double val = XFixedToDouble(kern[2 + j * wid + k]);
|
||||||
if (0.0 == val)
|
if (0.0 == val)
|
||||||
continue;
|
continue;
|
||||||
sum += val;
|
sum += val;
|
||||||
sprintf(pc, shader_add, val, texture_func, j - wid / 2, i - hei / 2);
|
sprintf(pc, shader_add, val, texture_func, k - wid / 2, j - hei / 2);
|
||||||
pc += strlen(pc);
|
pc += strlen(pc);
|
||||||
assert(strlen(shader_str) < len);
|
assert(strlen(shader_str) < len);
|
||||||
}
|
}
|
||||||
@ -267,41 +298,41 @@ glx_init_blur(session_t *ps) {
|
|||||||
|
|
||||||
sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum);
|
sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum);
|
||||||
assert(strlen(shader_str) < len);
|
assert(strlen(shader_str) < len);
|
||||||
#ifdef DEBUG_GLX_GLSL
|
|
||||||
fputs(shader_str, stdout);
|
|
||||||
fflush(stdout);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
ps->glx_frag_shader_blur = glx_create_shader(GL_FRAGMENT_SHADER, shader_str);
|
ppass->frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, shader_str);
|
||||||
free(extension);
|
|
||||||
free(shader_str);
|
free(shader_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ps->glx_frag_shader_blur) {
|
if (!ppass->frag_shader) {
|
||||||
printf_errf("(): Failed to create fragment shader.");
|
printf_errf("(): Failed to create fragment shader %d.", i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->glx_prog_blur = glx_create_program(&ps->glx_frag_shader_blur, 1);
|
// Build program
|
||||||
if (!ps->glx_prog_blur) {
|
ppass->prog = glx_create_program(&ppass->frag_shader, 1);
|
||||||
|
if (!ppass->prog) {
|
||||||
printf_errf("(): Failed to create GLSL program.");
|
printf_errf("(): Failed to create GLSL program.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get uniform addresses
|
||||||
#define P_GET_UNIFM_LOC(name, target) { \
|
#define P_GET_UNIFM_LOC(name, target) { \
|
||||||
ps->target = glGetUniformLocation(ps->glx_prog_blur, name); \
|
ppass->target = glGetUniformLocation(ppass->prog, name); \
|
||||||
if (ps->target < 0) { \
|
if (ppass->target < 0) { \
|
||||||
printf_errf("(): Failed to get location of uniform '" name "'. Might be troublesome."); \
|
printf_errf("(): Failed to get location of %d-th uniform '" name "'. Might be troublesome.", i); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
P_GET_UNIFM_LOC("factor_center", glx_prog_blur_unifm_factor_center);
|
P_GET_UNIFM_LOC("factor_center", unifm_factor_center);
|
||||||
if (!ps->o.glx_use_gpushader4) {
|
if (!ps->o.glx_use_gpushader4) {
|
||||||
P_GET_UNIFM_LOC("offset_x", glx_prog_blur_unifm_offset_x);
|
P_GET_UNIFM_LOC("offset_x", unifm_offset_x);
|
||||||
P_GET_UNIFM_LOC("offset_y", glx_prog_blur_unifm_offset_y);
|
P_GET_UNIFM_LOC("offset_y", unifm_offset_y);
|
||||||
|
}
|
||||||
|
#undef P_GET_UNIFM_LOC
|
||||||
|
}
|
||||||
|
free(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef P_GET_UNIFM_LOC
|
|
||||||
|
|
||||||
#ifdef DEBUG_GLX_ERR
|
#ifdef DEBUG_GLX_ERR
|
||||||
glx_check_err(ps);
|
glx_check_err(ps);
|
||||||
@ -841,9 +872,9 @@ glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
|||||||
} \
|
} \
|
||||||
glBegin(GL_QUADS); \
|
glBegin(GL_QUADS); \
|
||||||
\
|
\
|
||||||
for (int i = 0; i < nrects; ++i) { \
|
for (int ri = 0; ri < nrects; ++ri) { \
|
||||||
XRectangle crect; \
|
XRectangle crect; \
|
||||||
rect_crop(&crect, &rects[i], &rec_all); \
|
rect_crop(&crect, &rects[ri], &rec_all); \
|
||||||
\
|
\
|
||||||
if (!crect.width || !crect.height) \
|
if (!crect.width || !crect.height) \
|
||||||
continue; \
|
continue; \
|
||||||
@ -856,21 +887,69 @@ glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
|||||||
cxfree(rects); \
|
cxfree(rects); \
|
||||||
free_region(ps, ®_new); \
|
free_region(ps, ®_new); \
|
||||||
|
|
||||||
bool
|
static inline GLuint
|
||||||
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) {
|
||||||
GLfloat factor_center, XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
|
GLuint tex = 0;
|
||||||
// Read destination pixels into a texture
|
glGenTextures(1, &tex);
|
||||||
GLuint tex_scr = 0;
|
if (!tex) return 0;
|
||||||
glGenTextures(1, &tex_scr);
|
glEnable(tex_tgt);
|
||||||
if (!tex_scr) {
|
glBindTexture(tex_tgt, tex);
|
||||||
printf_errf("(): Failed to allocate texture.");
|
glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
return false;
|
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_RGB,
|
||||||
|
GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glBindTexture(tex_tgt, 0);
|
||||||
|
|
||||||
|
return tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int basex, int basey,
|
||||||
|
int dx, int dy, int width, int height) {
|
||||||
|
if (width > 0 && height > 0)
|
||||||
|
glCopyTexSubImage2D(tex_tgt, 0, dx - basex, dy - basey,
|
||||||
|
dx, ps->root_height - dy - height, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
||||||
|
/**
|
||||||
|
* Blur contents in a particular region.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
|
GLfloat factor_center,
|
||||||
|
XserverRegion reg_tgt, const reg_data_t *pcache_reg,
|
||||||
|
glx_blur_cache_t *pbc) {
|
||||||
|
assert(ps->glx_blur_passes[0].prog);
|
||||||
|
const bool more_passes = ps->glx_blur_passes[1].prog;
|
||||||
|
const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
// Calculate copy region size
|
||||||
|
glx_blur_cache_t ibc = { .width = 0, .height = 0 };
|
||||||
|
if (!pbc)
|
||||||
|
pbc = &ibc;
|
||||||
|
|
||||||
int mdx = dx, mdy = dy, mwidth = width, mheight = height;
|
int mdx = dx, mdy = dy, mwidth = width, mheight = height;
|
||||||
|
#ifdef DEBUG_GLX
|
||||||
|
printf_dbgf("(): %d, %d, %d, %d\n", mdx, mdy, mwidth, mheight);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
if (ps->o.resize_damage > 0) {
|
if (ps->o.resize_damage > 0) {
|
||||||
int inc_x = min_i(ps->o.resize_damage, XFixedToDouble(ps->o.blur_kern[0]) / 2),
|
int inc_x = 0, inc_y = 0;
|
||||||
inc_y = min_i(ps->o.resize_damage, XFixedToDouble(ps->o.blur_kern[1]) / 2);
|
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
|
||||||
|
XFixed *kern = ps->o.blur_kerns[i];
|
||||||
|
if (!kern) break;
|
||||||
|
inc_x += XFixedToDouble(kern[0]) / 2;
|
||||||
|
inc_y += XFixedToDouble(kern[1]) / 2;
|
||||||
|
}
|
||||||
|
inc_x = min_i(ps->o.resize_damage, inc_x);
|
||||||
|
inc_y = min_i(ps->o.resize_damage, inc_y);
|
||||||
|
|
||||||
mdx = max_i(dx - inc_x, 0);
|
mdx = max_i(dx - inc_x, 0);
|
||||||
mdy = max_i(dy - inc_y, 0);
|
mdy = max_i(dy - inc_y, 0);
|
||||||
int mdx2 = min_i(dx + width + inc_x, ps->root_width),
|
int mdx2 = min_i(dx + width + inc_x, ps->root_width),
|
||||||
@ -878,23 +957,56 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||||||
mwidth = mdx2 - mdx;
|
mwidth = mdx2 - mdx;
|
||||||
mheight = mdy2 - mdy;
|
mheight = mdy2 - mdy;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
|
GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
|
||||||
if (ps->glx_has_texture_non_power_of_two)
|
if (ps->glx_has_texture_non_power_of_two)
|
||||||
tex_tgt = GL_TEXTURE_2D;
|
tex_tgt = GL_TEXTURE_2D;
|
||||||
|
|
||||||
|
// Free textures if size inconsistency discovered
|
||||||
|
if (mwidth != pbc->width || mheight != pbc->height)
|
||||||
|
free_glx_bc_resize(ps, pbc);
|
||||||
|
|
||||||
|
// Generate FBO and textures if needed
|
||||||
|
if (!pbc->textures[0])
|
||||||
|
pbc->textures[0] = glx_gen_texture(ps, tex_tgt, mwidth, mheight);
|
||||||
|
GLuint tex_scr = pbc->textures[0];
|
||||||
|
if (more_passes && !pbc->textures[1])
|
||||||
|
pbc->textures[1] = glx_gen_texture(ps, tex_tgt, mwidth, mheight);
|
||||||
|
pbc->width = mwidth;
|
||||||
|
pbc->height = mheight;
|
||||||
|
GLuint tex_scr2 = pbc->textures[1];
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
if (more_passes && !pbc->fbo)
|
||||||
|
glGenFramebuffers(1, &pbc->fbo);
|
||||||
|
const GLuint fbo = pbc->fbo;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!tex_scr || (more_passes && !tex_scr2)) {
|
||||||
|
printf_errf("(): Failed to allocate texture.");
|
||||||
|
goto glx_blur_dst_end;
|
||||||
|
}
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
if (more_passes && !fbo) {
|
||||||
|
printf_errf("(): Failed to allocate framebuffer.");
|
||||||
|
goto glx_blur_dst_end;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Read destination pixels into a texture
|
||||||
glEnable(tex_tgt);
|
glEnable(tex_tgt);
|
||||||
glBindTexture(tex_tgt, tex_scr);
|
glBindTexture(tex_tgt, tex_scr);
|
||||||
glTexParameteri(tex_tgt, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, mheight);
|
||||||
glTexParameteri(tex_tgt, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
/*
|
||||||
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
if (tex_scr2) {
|
||||||
glTexParameteri(tex_tgt, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glBindTexture(tex_tgt, tex_scr2);
|
||||||
glTexImage2D(tex_tgt, 0, GL_RGB, mwidth, mheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, dx - mdx);
|
||||||
glCopyTexSubImage2D(tex_tgt, 0, 0, 0, mdx, ps->root_height - mdy - mheight, mwidth, mheight);
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy + height,
|
||||||
|
mwidth, mdy + mheight - dy - height);
|
||||||
#ifdef DEBUG_GLX
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy, dx - mdx, height);
|
||||||
printf_dbgf("(): %d, %d, %d, %d\n", mdx, ps->root_height - mdy - mheight, mwidth, mheight);
|
glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, dx + width, dy,
|
||||||
#endif
|
mdx + mwidth - dx - width, height);
|
||||||
|
} */
|
||||||
|
|
||||||
// Texture scaling factor
|
// Texture scaling factor
|
||||||
GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
|
GLfloat texfac_x = 1.0f, texfac_y = 1.0f;
|
||||||
@ -904,21 +1016,57 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paint it back
|
// Paint it back
|
||||||
|
if (more_passes) {
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool last_pass = false;
|
||||||
|
for (int i = 0; !last_pass; ++i) {
|
||||||
|
last_pass = !ps->glx_blur_passes[i + 1].prog;
|
||||||
|
assert(i < MAX_BLUR_PASS - 1);
|
||||||
|
const glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
|
||||||
|
assert(ppass->prog);
|
||||||
|
|
||||||
|
assert(tex_scr);
|
||||||
|
glBindTexture(tex_tgt, tex_scr);
|
||||||
|
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
if (!last_pass) {
|
||||||
|
static const GLenum DRAWBUFS[2] = { GL_COLOR_ATTACHMENT0 };
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_scr2, 0);
|
||||||
|
glDrawBuffers(1, DRAWBUFS);
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER)
|
||||||
|
!= GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
printf_errf("(): Framebuffer attachment failed.");
|
||||||
|
goto glx_blur_dst_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
static const GLenum DRAWBUFS[2] = { GL_BACK };
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glDrawBuffers(1, DRAWBUFS);
|
||||||
|
if (have_scissors)
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
if (have_stencil)
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Color negation for testing...
|
// Color negation for testing...
|
||||||
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||||
// glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
// glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
||||||
// glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
// glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
|
||||||
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
glUseProgram(ppass->prog);
|
||||||
glUseProgram(ps->glx_prog_blur);
|
if (ppass->unifm_offset_x >= 0)
|
||||||
if (ps->glx_prog_blur_unifm_offset_x >= 0)
|
glUniform1f(ppass->unifm_offset_x, texfac_x);
|
||||||
glUniform1f(ps->glx_prog_blur_unifm_offset_x, texfac_x);
|
if (ppass->unifm_offset_y >= 0)
|
||||||
if (ps->glx_prog_blur_unifm_offset_y >= 0)
|
glUniform1f(ppass->unifm_offset_y, texfac_y);
|
||||||
glUniform1f(ps->glx_prog_blur_unifm_offset_y, texfac_y);
|
if (ppass->unifm_factor_center >= 0)
|
||||||
if (ps->glx_prog_blur_unifm_factor_center >= 0)
|
glUniform1f(ppass->unifm_factor_center, factor_center);
|
||||||
glUniform1f(ps->glx_prog_blur_unifm_factor_center, factor_center);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
{
|
||||||
P_PAINTREG_START();
|
P_PAINTREG_START();
|
||||||
@ -927,13 +1075,20 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||||||
const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y;
|
const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y;
|
||||||
const GLfloat rxe = rx + crect.width * texfac_x;
|
const GLfloat rxe = rx + crect.width * texfac_x;
|
||||||
const GLfloat rye = ry - crect.height * texfac_y;
|
const GLfloat rye = ry - crect.height * texfac_y;
|
||||||
const GLfloat rdx = crect.x;
|
GLfloat rdx = crect.x - mdx;
|
||||||
const GLfloat rdy = ps->root_height - crect.y;
|
GLfloat rdy = mheight - crect.y + mdy;
|
||||||
const GLfloat rdxe = rdx + crect.width;
|
GLfloat rdxe = rdx + crect.width;
|
||||||
const GLfloat rdye = rdy - crect.height;
|
GLfloat rdye = rdy - crect.height;
|
||||||
|
|
||||||
|
if (last_pass) {
|
||||||
|
rdx = crect.x;
|
||||||
|
rdy = ps->root_height - crect.y;
|
||||||
|
rdxe = rdx + crect.width;
|
||||||
|
rdye = rdy - crect.height;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_GLX
|
#ifdef DEBUG_GLX
|
||||||
printf_dbgf("(): %f, %f, %f, %f -> %d, %d, %d, %d\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
printf_dbgf("(): %f, %f, %f, %f -> %f, %f, %f, %f\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glTexCoord2f(rx, ry);
|
glTexCoord2f(rx, ry);
|
||||||
@ -951,20 +1106,40 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||||||
P_PAINTREG_END();
|
P_PAINTREG_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VSYNC_OPENGL_GLSL
|
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
|
// Swap tex_scr and tex_scr2
|
||||||
|
{
|
||||||
|
GLuint tmp = tex_scr2;
|
||||||
|
tex_scr2 = tex_scr;
|
||||||
|
tex_scr = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
glx_blur_dst_end:
|
||||||
|
#ifdef CONFIG_VSYNC_OPENGL_FBO
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
#endif
|
#endif
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
glBindTexture(tex_tgt, 0);
|
glBindTexture(tex_tgt, 0);
|
||||||
glDeleteTextures(1, &tex_scr);
|
|
||||||
glDisable(tex_tgt);
|
glDisable(tex_tgt);
|
||||||
|
if (have_scissors)
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
if (have_stencil)
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
if (&ibc == pbc) {
|
||||||
|
free_glx_bc(ps, pbc);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_GLX_ERR
|
#ifdef DEBUG_GLX_ERR
|
||||||
glx_check_err(ps);
|
glx_check_err(ps);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
@ -1156,7 +1331,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_GLX
|
#ifdef DEBUG_GLX
|
||||||
printf_dbgf("(): Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d\n", i, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
printf_dbgf("(): Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d\n", ri, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define P_TEXCOORD(cx, cy) { \
|
#define P_TEXCOORD(cx, cy) { \
|
||||||
@ -1318,6 +1493,11 @@ 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) {
|
||||||
|
#ifdef DEBUG_GLX_GLSL
|
||||||
|
printf("glx_create_shader(): ===\n%s\n===\n", shader_str);
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
GLuint shader = glCreateShader(shader_type);
|
GLuint shader = glCreateShader(shader_type);
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
|
Loading…
Reference in New Issue
Block a user