Last active
December 17, 2015 10:59
-
-
Save richardgv/5598712 to your computer and use it in GitHub Desktop.
chjj/compton: D-Bus fading control & Multi-pass blur (WIP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Makefile b/Makefile | |
index db7a272..d94783d 100644 | |
--- a/Makefile | |
+++ b/Makefile | |
@@ -52,6 +52,12 @@ ifeq "$(NO_VSYNC_OPENGL)" "" | |
ifeq "$(NO_VSYNC_OPENGL_GLSL)" "" | |
CFG += -DCONFIG_VSYNC_OPENGL_GLSL | |
endif | |
+ ifeq "$(NO_VSYNC_OPENGL_FBO)" "" | |
+ CFG += -DCONFIG_VSYNC_OPENGL_FBO | |
+ endif | |
+ ifeq "$(NO_VSYNC_OPENGL_VBO)" "" | |
+ CFG += -DCONFIG_VSYNC_OPENGL_VBO | |
+ endif | |
endif | |
# ==== D-Bus ==== | |
diff --git a/README.md b/README.md | |
index 8c1645b..00eae45 100644 | |
--- a/README.md | |
+++ b/README.md | |
@@ -77,7 +77,7 @@ $ make install | |
## 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. | |
diff --git a/src/common.h b/src/common.h | |
index bf9f8ae..2818f75 100644 | |
--- a/src/common.h | |
+++ b/src/common.h | |
@@ -26,6 +26,10 @@ | |
// #define DEBUG_FRAME 1 | |
// #define DEBUG_LEADER 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 | |
// Whether to enable PCRE regular expression support in blacklists, enabled | |
@@ -40,8 +44,12 @@ | |
// #define CONFIG_LIBCONFIG_LEGACY 1 | |
// Whether to enable DRM VSync support | |
// #define CONFIG_VSYNC_DRM 1 | |
-// Whether to enable OpenGL VSync support | |
+// Whether to enable OpenGL support | |
// #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. | |
// #define CONFIG_DBUS 1 | |
// Whether to enable condition support. | |
@@ -183,6 +191,9 @@ | |
/// @brief Maximum OpenGL buffer age. | |
#define CGLX_MAX_BUFFER_AGE 5 | |
+/// @brief Maximum passes for blur. | |
+#define MAX_BLUR_PASS 5 | |
+ | |
// Window flags | |
// Window size is changed | |
@@ -343,6 +354,32 @@ struct _glx_texture { | |
}; | |
#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 { | |
Pixmap pixmap; | |
Picture pict; | |
@@ -501,7 +538,7 @@ typedef struct { | |
/// Background blur blacklist. A linked list of conditions. | |
c2_lptr_t *blur_background_blacklist; | |
/// 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. | |
double inactive_dim; | |
/// Whether to use fixed inactive dim opacity, instead of deciding | |
@@ -702,16 +739,7 @@ typedef struct { | |
/// FBConfig-s for GLX pixmap of different depths. | |
glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1]; | |
#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
- /// Fragment shader for blur. | |
- 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; | |
+ glx_blur_pass_t glx_blur_passes[MAX_BLUR_PASS]; | |
#endif | |
#endif | |
@@ -908,6 +936,8 @@ typedef struct _win { | |
/// Do not fade if it's false. Change on window type change. | |
/// Used by fading blacklist in the future. | |
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. | |
void (*fade_callback) (session_t *ps, struct _win *w); | |
@@ -950,6 +980,11 @@ typedef struct _win { | |
/// Whether to blur window background. | |
bool blur_background; | |
+ | |
+#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
+ /// Textures background blur use. | |
+ glx_blur_cache_t glx_blur_cache; | |
+#endif | |
} win; | |
/// Temporary structure used for communication between | |
@@ -1749,6 +1784,9 @@ force_repaint(session_t *ps); | |
bool | |
vsync_init(session_t *ps); | |
+void | |
+vsync_deinit(session_t *ps); | |
+ | |
#ifdef CONFIG_VSYNC_OPENGL | |
/** @name GLX | |
*/ | |
@@ -1790,7 +1828,9 @@ glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg); | |
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); | |
+ GLfloat factor_center, | |
+ XserverRegion reg_tgt, const reg_data_t *pcache_reg, | |
+ glx_blur_cache_t *pbc); | |
bool | |
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z, | |
@@ -1846,6 +1886,23 @@ glx_mark_frame(session_t *ps) { | |
#endif | |
} | |
+#ifdef CONFIG_VSYNC_OPENGL | |
+/** | |
+ * 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; | |
+ } | |
+} | |
+#endif | |
+ | |
+/** | |
+ * Free a glx_texture_t. | |
+ */ | |
static inline void | |
free_texture(session_t *ps, glx_texture_t **pptex) { | |
#ifdef CONFIG_VSYNC_OPENGL | |
@@ -1857,11 +1914,7 @@ free_texture(session_t *ps, glx_texture_t **pptex) { | |
glx_release_pixmap(ps, ptex); | |
- // Free texture | |
- if (ptex->texture) { | |
- glDeleteTextures(1, &ptex->texture); | |
- ptex->texture = 0; | |
- } | |
+ free_texture_r(ps, &ptex->texture); | |
// Free structure itself | |
free(ptex); | |
@@ -1869,6 +1922,40 @@ free_texture(session_t *ps, glx_texture_t **pptex) { | |
#endif | |
} | |
+/** | |
+ * 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 | |
+ 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]); | |
+} | |
+ | |
+/** | |
+ * 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 | |
+ | |
///@} | |
/** @name DBus handling | |
@@ -1913,6 +2000,9 @@ void | |
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 | |
win_set_focused_force(session_t *ps, win *w, switch_t val); | |
void | |
@@ -1920,6 +2010,9 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val); | |
void | |
opts_init_track_focus(session_t *ps); | |
+ | |
+void | |
+opts_set_no_fading_openclose(session_t *ps, bool newval); | |
//!@} | |
#endif | |
diff --git a/src/compton.c b/src/compton.c | |
index 7e005b6..6b5fbc9 100644 | |
--- a/src/compton.c | |
+++ b/src/compton.c | |
@@ -70,6 +70,14 @@ static int (* const (VSYNC_FUNCS_WAIT[NUM_VSYNC]))(session_t *ps) = { | |
#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 | |
/// background. | |
const static char *background_props_str[] = { | |
@@ -1328,12 +1336,13 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, | |
if (!tmp_picture) | |
return; | |
- XFixed *convolution_blur = ps->o.blur_kern; | |
- int kwid = XFixedToDouble((ps->o.blur_kern[0])), | |
- khei = XFixedToDouble((ps->o.blur_kern[1])); | |
+ XFixed *convolution_blur = ps->o.blur_kerns[0]; | |
+ int kwid = XFixedToDouble((convolution_blur[0])), | |
+ khei = XFixedToDouble((convolution_blur[1])); | |
// Modify the factor of the center pixel | |
- convolution_blur[2 + (khei / 2) * kwid + kwid / 2] = XDoubleToFixed(factor_center); | |
+ convolution_blur[2 + (khei / 2) * kwid + kwid / 2] = | |
+ XDoubleToFixed(factor_center); | |
// Minimize the region we try to blur, if the window itself is not | |
// opaque, only the frame is. | |
@@ -1359,8 +1368,9 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, | |
break; | |
#ifdef CONFIG_VSYNC_OPENGL | |
case BKEND_GLX: | |
+ // TODO: Handle frame opacity | |
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; | |
#endif | |
default: | |
@@ -1993,14 +2003,8 @@ map_win(session_t *ps, Window id) { | |
win_determine_shadow(ps, w); | |
// 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; | |
- } | |
- else { | |
- set_fade_callback(ps, w, NULL, true); | |
- } | |
+ w->in_openclose = true; | |
+ set_fade_callback(ps, w, finish_map_win, true); | |
win_determine_fade(ps, w); | |
win_determine_blur_background(ps, w); | |
@@ -2066,9 +2070,7 @@ unmap_win(session_t *ps, win *w) { | |
// Fading out | |
w->flags |= WFLAG_OPCT_CHANGE; | |
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); | |
// Validate pixmap if we have to do fading | |
@@ -2195,7 +2197,9 @@ calc_dim(session_t *ps, win *w) { | |
*/ | |
static void | |
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)) | |
w->fade = false; | |
else | |
@@ -2593,6 +2597,7 @@ add_win(session_t *ps, Window id, Window prev) { | |
.opacity_prop_client = OPAQUE, | |
.fade = false, | |
+ .fade_force = UNSET, | |
.fade_callback = NULL, | |
.frame_opacity = 0.0, | |
@@ -3418,6 +3423,19 @@ win_set_shadow_force(session_t *ps, win *w, switch_t val) { | |
if (val != w->shadow_force) { | |
w->shadow_force = val; | |
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 +3447,7 @@ win_set_focused_force(session_t *ps, win *w, switch_t val) { | |
if (val != w->focused_force) { | |
w->focused_force = val; | |
win_update_focused(ps, w); | |
+ ps->ev_received = true; | |
} | |
} | |
@@ -3440,6 +3459,7 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val) { | |
if (val != w->invert_color_force) { | |
w->invert_color_force = val; | |
win_determine_invert_color(ps, w); | |
+ ps->ev_received = true; | |
} | |
} | |
@@ -3465,6 +3485,20 @@ opts_init_track_focus(session_t *ps) { | |
// Recheck focus | |
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 | |
@@ -4419,7 +4453,7 @@ parse_matrix_readnum(const char *src, double *dest) { | |
* Parse a matrix. | |
*/ | |
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; | |
const char *pc = NULL; | |
XFixed *matrix = NULL; | |
@@ -4481,12 +4515,28 @@ parse_matrix(session_t *ps, const char *src) { | |
} | |
// Detect trailing characters | |
- for ( ;*pc; ++pc) | |
+ for ( ;*pc && ';' != *pc; ++pc) | |
if (!isspace(*pc) && ',' != *pc) { | |
printf_errf("(): Trailing characters in matrix string."); | |
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 | |
matrix[0] = XDoubleToFixed(wid); | |
matrix[1] = XDoubleToFixed(hei); | |
@@ -4502,7 +4552,12 @@ parse_matrix_err: | |
* Parse a convolution kernel. | |
*/ | |
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 { | |
const char *name; | |
const char *kern_str; | |
@@ -4519,8 +4574,30 @@ parse_conv_kern(session_t *ps, const char *src) { | |
for (int i = 0; | |
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) | |
if (!strcmp(CONV_KERN_PREDEF[i].name, src)) | |
- return parse_matrix(ps, CONV_KERN_PREDEF[i].kern_str); | |
- return parse_matrix(ps, src); | |
+ return parse_conv_kern_lst(ps, CONV_KERN_PREDEF[i].kern_str, dest, max); | |
+ | |
+ 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 | |
@@ -5115,9 +5192,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { | |
break; | |
case 301: | |
// --blur-kern | |
- free(ps->o.blur_kern); | |
- if (!(ps->o.blur_kern = parse_conv_kern(ps, optarg))) | |
+ if (!parse_conv_kern_lst(ps, optarg, ps->o.blur_kerns, MAX_BLUR_PASS)) | |
exit(1); | |
+ break; | |
case 302: | |
// --resize-damage | |
ps->o.resize_damage = atoi(optarg); | |
@@ -5187,7 +5264,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { | |
} | |
// 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) | |
// gaussian or binomial filters are definitely superior, yet looks | |
// like they aren't supported as of xorg-server-1.13.0 | |
@@ -5200,12 +5277,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), | |
}; | |
- ps->o.blur_kern = malloc(sizeof(convolution_blur)); | |
- if (!ps->o.blur_kern) { | |
+ ps->o.blur_kerns[0] = malloc(sizeof(convolution_blur)); | |
+ if (!ps->o.blur_kerns[0]) { | |
printf_errf("(): Failed to allocate memory for convolution kernel."); | |
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 +5613,19 @@ vsync_opengl_oml_wait(session_t *ps) { | |
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 | |
/** | |
@@ -5565,6 +5655,16 @@ vsync_wait(session_t *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. | |
*/ | |
static void | |
@@ -6030,7 +6130,7 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
.blur_background_frame = false, | |
.blur_background_fixed = false, | |
.blur_background_blacklist = NULL, | |
- .blur_kern = NULL, | |
+ .blur_kerns = { NULL }, | |
.inactive_dim = 0.0, | |
.inactive_dim_fixed = false, | |
.invert_color_list = NULL, | |
@@ -6096,12 +6196,6 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
.glXWaitVideoSyncSGI = NULL, | |
.glXGetSyncValuesOML = 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 | |
.xfixes_event = 0, | |
@@ -6151,6 +6245,14 @@ session_init(session_t *ps_old, int argc, char **argv) { | |
// Allocate a session and copy default values into it | |
session_t *ps = malloc(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->ignore_tail = &ps->ignore_head; | |
gettimeofday(&ps->time_start, NULL); | |
@@ -6513,7 +6615,8 @@ session_destroy(session_t *ps) { | |
free(ps->o.display); | |
free(ps->o.logpath); | |
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->pfds_read); | |
free(ps->pfds_write); | |
free(ps->pfds_except); | |
diff --git a/src/compton.h b/src/compton.h | |
index 24325ab..2a6d3cb 100644 | |
--- a/src/compton.h | |
+++ b/src/compton.h | |
@@ -231,6 +231,9 @@ free_win_res(session_t *ps, win *w) { | |
free(w->class_instance); | |
free(w->class_general); | |
free(w->role); | |
+#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
+ free_glx_bc(ps, &w->glx_blur_cache); | |
+#endif | |
} | |
/** | |
@@ -1095,6 +1098,12 @@ vsync_opengl_wait(session_t *ps); | |
static int | |
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 | |
static void | |
diff --git a/src/dbus.c b/src/dbus.c | |
index e48aa1a..f2b019a 100644 | |
--- a/src/dbus.c | |
+++ b/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(leader, cdbus_reply_wid); | |
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(focused_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; | |
} | |
- ps->ev_received = true; | |
- | |
#define cdbus_m_win_set_do(tgt, type, real_type) \ | |
if (!strcmp(MSTR(tgt), target)) { \ | |
real_type val; \ | |
@@ -789,6 +788,14 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg) { | |
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)) { | |
cdbus_enum_t val = UNSET; | |
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(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_frame, 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; \ | |
} | |
+ // 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 | |
if (!strcmp("unredir_if_possible", target)) { | |
dbus_bool_t val = FALSE; | |
@@ -1002,6 +1050,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) { | |
const char * val = NULL; | |
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_STRING, &val)) | |
return false; | |
+ vsync_deinit(ps); | |
if (!parse_vsync(ps, val)) { | |
printf_errf("(): " CDBUS_ERROR_BADARG_S, 1, "Value invalid."); | |
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADARG, CDBUS_ERROR_BADARG_S, 1, "Value invalid."); | |
diff --git a/src/opengl.c b/src/opengl.c | |
index edd6151..cbf362a 100644 | |
--- a/src/opengl.c | |
+++ b/src/opengl.c | |
@@ -160,10 +160,13 @@ void | |
glx_destroy(session_t *ps) { | |
#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
// Free GLSL shaders/programs | |
- if (ps->glx_frag_shader_blur) | |
- glDeleteShader(ps->glx_frag_shader_blur); | |
- if (ps->glx_prog_blur) | |
- glDeleteProgram(ps->glx_prog_blur); | |
+ for (int i = 0; i < MAX_BLUR_PASS; ++i) { | |
+ glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; | |
+ if (ppass->frag_shader) | |
+ glDeleteShader(ppass->frag_shader); | |
+ if (ppass->prog) | |
+ glDeleteProgram(ppass->prog); | |
+ } | |
#endif | |
// Free FBConfigs | |
@@ -199,8 +202,28 @@ glx_on_root_change(session_t *ps) { | |
*/ | |
bool | |
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 | |
- // Build shader | |
{ | |
static const char *FRAG_SHADER_BLUR_PREFIX = | |
"#version 110\n" | |
@@ -235,73 +258,81 @@ glx_init_blur(session_t *ps) { | |
shader_add = FRAG_SHADER_BLUR_ADD_GPUSHADER4; | |
} | |
- int wid = XFixedToDouble(ps->o.blur_kern[0]), | |
- hei = XFixedToDouble(ps->o.blur_kern[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; | |
- char *shader_str = calloc(len, sizeof(char)); | |
- if (!shader_str) { | |
- printf_errf("(): Failed to allocate %d bytes for shader string.", len); | |
- return false; | |
- } | |
- { | |
- char *pc = shader_str; | |
- sprintf(pc, FRAG_SHADER_BLUR_PREFIX, extension, sampler_type); | |
- pc += strlen(pc); | |
- assert(strlen(shader_str) < len); | |
- | |
- double sum = 0.0; | |
- for (int i = 0; i < hei; ++i) { | |
- for (int j = 0; j < wid; ++j) { | |
- if (hei / 2 == i && wid / 2 == j) | |
- continue; | |
- double val = XFixedToDouble(ps->o.blur_kern[2 + i * wid + j]); | |
- if (0.0 == val) | |
- continue; | |
- sum += val; | |
- sprintf(pc, shader_add, val, texture_func, j - wid / 2, i - hei / 2); | |
+ for (int i = 0; i < MAX_BLUR_PASS && ps->o.blur_kerns[i]; ++i) { | |
+ 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 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)); | |
+ if (!shader_str) { | |
+ printf_errf("(): Failed to allocate %d bytes for shader string.", len); | |
+ return false; | |
+ } | |
+ { | |
+ char *pc = shader_str; | |
+ sprintf(pc, FRAG_SHADER_BLUR_PREFIX, extension, sampler_type); | |
pc += strlen(pc); | |
assert(strlen(shader_str) < len); | |
+ | |
+ double sum = 0.0; | |
+ for (int j = 0; j < hei; ++j) { | |
+ for (int k = 0; k < wid; ++k) { | |
+ if (hei / 2 == j && wid / 2 == k) | |
+ continue; | |
+ double val = XFixedToDouble(kern[2 + j * wid + k]); | |
+ if (0.0 == val) | |
+ continue; | |
+ sum += val; | |
+ sprintf(pc, shader_add, val, texture_func, k - wid / 2, j - hei / 2); | |
+ pc += strlen(pc); | |
+ assert(strlen(shader_str) < len); | |
+ } | |
+ } | |
+ | |
+ sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum); | |
+ assert(strlen(shader_str) < len); | |
} | |
+ ppass->frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, shader_str); | |
+ free(shader_str); | |
} | |
- sprintf(pc, FRAG_SHADER_BLUR_SUFFIX, texture_func, sum); | |
- 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); | |
- free(extension); | |
- free(shader_str); | |
- } | |
- | |
- if (!ps->glx_frag_shader_blur) { | |
- printf_errf("(): Failed to create fragment shader."); | |
- return false; | |
- } | |
+ if (!ppass->frag_shader) { | |
+ printf_errf("(): Failed to create fragment shader %d.", i); | |
+ return false; | |
+ } | |
- ps->glx_prog_blur = glx_create_program(&ps->glx_frag_shader_blur, 1); | |
- if (!ps->glx_prog_blur) { | |
- printf_errf("(): Failed to create GLSL program."); | |
- return false; | |
- } | |
+ // Build program | |
+ ppass->prog = glx_create_program(&ppass->frag_shader, 1); | |
+ if (!ppass->prog) { | |
+ printf_errf("(): Failed to create GLSL program."); | |
+ return false; | |
+ } | |
+ // Get uniform addresses | |
#define P_GET_UNIFM_LOC(name, target) { \ | |
- ps->target = glGetUniformLocation(ps->glx_prog_blur, name); \ | |
- if (ps->target < 0) { \ | |
- printf_errf("(): Failed to get location of uniform '" name "'. Might be troublesome."); \ | |
- } \ | |
-} | |
+ ppass->target = glGetUniformLocation(ppass->prog, name); \ | |
+ if (ppass->target < 0) { \ | |
+ 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); | |
- if (!ps->o.glx_use_gpushader4) { | |
- P_GET_UNIFM_LOC("offset_x", glx_prog_blur_unifm_offset_x); | |
- P_GET_UNIFM_LOC("offset_y", glx_prog_blur_unifm_offset_y); | |
+ P_GET_UNIFM_LOC("factor_center", unifm_factor_center); | |
+ if (!ps->o.glx_use_gpushader4) { | |
+ P_GET_UNIFM_LOC("offset_x", unifm_offset_x); | |
+ 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 | |
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); \ | |
\ | |
- for (int i = 0; i < nrects; ++i) { \ | |
+ for (int ri = 0; ri < nrects; ++ri) { \ | |
XRectangle crect; \ | |
- rect_crop(&crect, &rects[i], &rec_all); \ | |
+ rect_crop(&crect, &rects[ri], &rec_all); \ | |
\ | |
if (!crect.width || !crect.height) \ | |
continue; \ | |
@@ -856,21 +887,67 @@ glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) { | |
cxfree(rects); \ | |
free_region(ps, ®_new); \ | |
+static inline GLuint | |
+glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) { | |
+ GLuint tex = 0; | |
+ glGenTextures(1, &tex); | |
+ if (!tex) return 0; | |
+ glEnable(tex_tgt); | |
+ glBindTexture(tex_tgt, tex); | |
+ 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_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, 0, 0, dx, ps->root_height - dy - height, | |
+ width, height); | |
+} | |
+ | |
+/** | |
+ * 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) { | |
- // 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; | |
- } | |
+ GLfloat factor_center, | |
+ XserverRegion reg_tgt, const reg_data_t *pcache_reg, | |
+ glx_blur_cache_t *pbc) { | |
+ 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; | |
+#ifdef DEBUG_GLX | |
+ printf_dbgf("(): %d, %d, %d, %d\n", mdx, mdy, mwidth, mheight); | |
+#endif | |
+ | |
+ /* | |
if (ps->o.resize_damage > 0) { | |
- int inc_x = min_i(ps->o.resize_damage, XFixedToDouble(ps->o.blur_kern[0]) / 2), | |
- inc_y = min_i(ps->o.resize_damage, XFixedToDouble(ps->o.blur_kern[1]) / 2); | |
+ int inc_x = 0, inc_y = 0; | |
+ 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); | |
mdy = max_i(dy - inc_y, 0); | |
int mdx2 = min_i(dx + width + inc_x, ps->root_width), | |
@@ -878,24 +955,57 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, | |
mwidth = mdx2 - mdx; | |
mheight = mdy2 - mdy; | |
} | |
+ */ | |
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, mwidth, mheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); | |
- glCopyTexSubImage2D(tex_tgt, 0, 0, 0, mdx, ps->root_height - mdy - mheight, mwidth, mheight); | |
+ // 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 | |
-#ifdef DEBUG_GLX | |
- printf_dbgf("(): %d, %d, %d, %d\n", mdx, ps->root_height - mdy - mheight, mwidth, mheight); | |
+ 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); | |
+ glBindTexture(tex_tgt, tex_scr); | |
+ glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, mheight); | |
+ if (tex_scr2) { | |
+ glBindTexture(tex_tgt, tex_scr2); | |
+ /* | |
+ glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, mdy, mwidth, dx - mdx); | |
+ glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy + height, | |
+ mwidth, mdy + mheight - dy - height); | |
+ glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, mdx, dy, dx - mdx, height); | |
+ glx_copy_region_to_tex(ps, tex_tgt, mdx, mdy, dx + width, dy, | |
+ mdx + mwidth - dx - width, height); */ | |
+ } | |
+ | |
// Texture scaling factor | |
GLfloat texfac_x = 1.0f, texfac_y = 1.0f; | |
if (GL_TEXTURE_2D == tex_tgt) { | |
@@ -904,66 +1014,134 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, | |
} | |
// Paint it back | |
- // Color negation for testing... | |
- // 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); | |
+ if (more_passes) { | |
+ glDisable(GL_STENCIL_TEST); | |
+ glDisable(GL_SCISSOR_TEST); | |
+ } | |
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
- glUseProgram(ps->glx_prog_blur); | |
- if (ps->glx_prog_blur_unifm_offset_x >= 0) | |
- glUniform1f(ps->glx_prog_blur_unifm_offset_x, texfac_x); | |
- if (ps->glx_prog_blur_unifm_offset_y >= 0) | |
- glUniform1f(ps->glx_prog_blur_unifm_offset_y, texfac_y); | |
- if (ps->glx_prog_blur_unifm_factor_center >= 0) | |
- glUniform1f(ps->glx_prog_blur_unifm_factor_center, factor_center); | |
+ bool last_pass = false; | |
+ for (int i = 0; !last_pass; ++i) { | |
+ last_pass = (i + 1 >= MAX_BLUR_PASS || !ps->glx_blur_passes[i + 1].prog); | |
+ 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 | |
- { | |
- P_PAINTREG_START(); | |
+ // Color negation for testing... | |
+ // 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); | |
+ | |
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
+ glUseProgram(ppass->prog); | |
+ if (ppass->unifm_offset_x >= 0) | |
+ glUniform1f(ppass->unifm_offset_x, texfac_x); | |
+ if (ppass->unifm_offset_y >= 0) | |
+ glUniform1f(ppass->unifm_offset_y, texfac_y); | |
+ if (ppass->unifm_factor_center >= 0) | |
+ glUniform1f(ppass->unifm_factor_center, factor_center); | |
+ | |
+ /* if (last_pass) { | |
+ glClearColor(1.0, 0.0, 0.0, 1.0); | |
+ glClear(GL_COLOR_BUFFER_BIT); | |
+ glClearColor(0.0, 0.0, 0.0, 1.0); | |
+ } */ | |
{ | |
- const GLfloat rx = (crect.x - mdx) * texfac_x; | |
- const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y; | |
- const GLfloat rxe = rx + crect.width * texfac_x; | |
- const GLfloat rye = ry - crect.height * texfac_y; | |
- const GLfloat rdx = crect.x; | |
- const GLfloat rdy = ps->root_height - crect.y; | |
- const GLfloat rdxe = rdx + crect.width; | |
- const GLfloat rdye = rdy - crect.height; | |
+ P_PAINTREG_START(); | |
+ { | |
+ const GLfloat rx = (crect.x - mdx) * texfac_x; | |
+ const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y; | |
+ const GLfloat rxe = rx + crect.width * texfac_x; | |
+ const GLfloat rye = ry - crect.height * texfac_y; | |
+ GLfloat rdx = crect.x - mdx; | |
+ GLfloat rdy = mheight - crect.y + mdy; | |
+ GLfloat rdxe = rdx + crect.width; | |
+ 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 | |
- 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 | |
- glTexCoord2f(rx, ry); | |
- glVertex3f(rdx, rdy, z); | |
+ glTexCoord2f(rx, ry); | |
+ glVertex3f(rdx, rdy, z); | |
- glTexCoord2f(rxe, ry); | |
- glVertex3f(rdxe, rdy, z); | |
+ glTexCoord2f(rxe, ry); | |
+ glVertex3f(rdxe, rdy, z); | |
- glTexCoord2f(rxe, rye); | |
- glVertex3f(rdxe, rdye, z); | |
+ glTexCoord2f(rxe, rye); | |
+ glVertex3f(rdxe, rdye, z); | |
- glTexCoord2f(rx, rye); | |
- glVertex3f(rdx, rdye, z); | |
+ glTexCoord2f(rx, rye); | |
+ glVertex3f(rdx, rdye, z); | |
+ } | |
+ P_PAINTREG_END(); | |
+ } | |
+ | |
+ glUseProgram(0); | |
+ | |
+ // Swap tex_scr and tex_scr2 | |
+ { | |
+ GLuint tmp = tex_scr2; | |
+ tex_scr2 = tex_scr; | |
+ tex_scr = tmp; | |
} | |
- P_PAINTREG_END(); | |
} | |
+#endif | |
-#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
- glUseProgram(0); | |
+ ret = true; | |
+ | |
+glx_blur_dst_end: | |
+#ifdef CONFIG_VSYNC_OPENGL_FBO | |
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
#endif | |
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | |
glBindTexture(tex_tgt, 0); | |
- glDeleteTextures(1, &tex_scr); | |
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 | |
glx_check_err(ps); | |
#endif | |
- return true; | |
+ return ret; | |
} | |
bool | |
@@ -1156,7 +1334,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex, | |
} | |
#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 | |
#define P_TEXCOORD(cx, cy) { \ | |
@@ -1318,6 +1496,11 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) { | |
#ifdef CONFIG_VSYNC_OPENGL_GLSL | |
GLuint | |
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; | |
GLuint shader = glCreateShader(shader_type); | |
if (!shader) { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment