summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Grenville <[email protected]>2014-05-16 15:18:17 +0800
committerRichard Grenville <[email protected]>2014-05-16 15:18:17 +0800
commit0fa155f566d7d1d290e4b922859410b5f76f9dfa (patch)
tree817e1582b3e197c0feeed7cc6ef7afa21bbbb7ae
parent12225bcad2ad98b011a809ec882452b9d0242caa (diff)
downloadtdebase-0fa155f566d7d1d290e4b922859410b5f76f9dfa.tar.gz
tdebase-0fa155f566d7d1d290e4b922859410b5f76f9dfa.zip
Feature: #183 custom window shader & #193 --no-fading-destroyed-argb
- Add --glx-fshader-win, which specifies a custom fragment shader for painting windows. compton-default-fshader-win.glsl is the shader with default behavior, and compton-fake-transparency-fshader-win.glsl provides a template of fake transparency. (#183) - Add --force-win-blend to force all windows to be painted with blending. - Add --no-fading-destroyed-argb, as a workaround of bugs in some WMs. (#193)
-rw-r--r--common.h76
-rw-r--r--compton.c73
-rw-r--r--compton.h27
-rw-r--r--opengl.c275
4 files changed, 352 insertions, 99 deletions
diff --git a/common.h b/common.h
index bbbfeae8e..0f8cc39ac 100644
--- a/common.h
+++ b/common.h
@@ -469,6 +469,25 @@ typedef struct {
/// Height of the textures.
int height;
} glx_blur_cache_t;
+
+typedef struct {
+ /// GLSL program.
+ GLuint prog;
+ /// Location of uniform "opacity" in window GLSL program.
+ GLint unifm_opacity;
+ /// Location of uniform "invert_color" in blur GLSL program.
+ GLint unifm_invert_color;
+ /// Location of uniform "tex" in window GLSL program.
+ GLint unifm_tex;
+} glx_prog_main_t;
+
+#define GLX_PROG_MAIN_INIT { \
+ .prog = 0, \
+ .unifm_opacity = -1, \
+ .unifm_invert_color = -1, \
+ .unifm_tex = -1, \
+}
+
#endif
typedef struct {
@@ -536,10 +555,12 @@ typedef struct _options_t {
int glx_swap_method;
/// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring.
bool glx_use_gpushader4;
- /// Whether to try to detect WM windows and mark them as focused.
- bool mark_wmwin_focused;
- /// Whether to mark override-redirect windows as focused.
- bool mark_ovredir_focused;
+ /// Custom fragment shader for painting windows, as a string.
+ char *glx_fshader_win_str;
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ /// Custom GLX program used for painting window.
+ glx_prog_main_t glx_prog_win;
+#endif
/// Whether to fork to background.
bool fork_after_register;
/// Whether to detect rounded corners.
@@ -547,6 +568,8 @@ typedef struct _options_t {
/// Whether to paint on X Composite overlay window instead of root
/// window.
bool paint_on_overlay;
+ /// Force painting of window content with blending.
+ bool force_win_blend;
/// Resize damage for a specific number of pixels.
int resize_damage;
/// Whether to unredirect all windows if a full-screen opaque window
@@ -622,6 +645,8 @@ typedef struct _options_t {
time_ms_t fade_delta;
/// Whether to disable fading on window open/close.
bool no_fading_openclose;
+ /// Whether to disable fading on ARGB managed destroyed windows.
+ bool no_fading_destroyed_argb;
/// Fading blacklist. A linked list of conditions.
c2_lptr_t *fade_blacklist;
@@ -672,6 +697,10 @@ typedef struct _options_t {
// === Focus related ===
/// Consider windows of specific types to be always focused.
bool wintype_focus[NUM_WINTYPES];
+ /// Whether to try to detect WM windows and mark them as focused.
+ bool mark_wmwin_focused;
+ /// Whether to mark override-redirect windows as focused.
+ bool mark_ovredir_focused;
/// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
bool use_ewmh_active_win;
/// A list of windows always to be considered focused.
@@ -1966,6 +1995,14 @@ win_is_fullscreen(session_t *ps, const win *w) {
}
/**
+ * Check if a window will be painted solid.
+ */
+static inline bool
+win_is_solid(session_t *ps, const win *w) {
+ return WMODE_SOLID == w->mode && !ps->o.force_win_blend;
+}
+
+/**
* Determine if a window has a specific property.
*
* @param ps current session
@@ -2073,6 +2110,13 @@ glx_on_root_change(session_t *ps);
bool
glx_init_blur(session_t *ps);
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+bool
+glx_load_prog_main(session_t *ps,
+ const char *vshader_str, const char *fshader_str,
+ glx_prog_main_t *pprogram);
+#endif
+
bool
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
unsigned width, unsigned height, unsigned depth);
@@ -2108,10 +2152,24 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
bool
-glx_render(session_t *ps, const glx_texture_t *ptex,
+glx_render_(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z,
- double opacity, bool neg,
- XserverRegion reg_tgt, const reg_data_t *pcache_reg);
+ double opacity, bool argb, bool neg,
+ XserverRegion reg_tgt, const reg_data_t *pcache_reg
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ , const glx_prog_main_t *pprogram
+#endif
+ );
+
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+#define \
+ glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
+ glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram)
+#else
+#define \
+ glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
+ glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg)
+#endif
void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
@@ -2122,6 +2180,10 @@ glx_create_shader(GLenum shader_type, const char *shader_str);
GLuint
glx_create_program(const GLuint * const shaders, int nshaders);
+
+GLuint
+glx_create_program_from_str(const char *vert_shader_str,
+ const char *frag_shader_str);
#endif
/**
diff --git a/compton.c b/compton.c
index eea986539..dce4d0963 100644
--- a/compton.c
+++ b/compton.c
@@ -1206,7 +1206,7 @@ paint_preprocess(session_t *ps, win *list) {
// If the window is solid, we add the window region to the
// ignored region
- if (WMODE_SOLID == w->mode) {
+ if (win_is_solid(ps, w)) {
if (!w->frame_opacity) {
if (w->border_size)
w->reg_ignore = copy_region(ps, w->border_size);
@@ -1240,7 +1240,7 @@ paint_preprocess(session_t *ps, win *list) {
// is not correctly set.
if (ps->o.unredir_if_possible && is_highest && to_paint) {
is_highest = false;
- if (WMODE_SOLID == w->mode
+ if (win_is_solid(ps, w)
&& (!w->frame_opacity || !win_has_frame(w))
&& win_is_fullscreen(ps, w)
&& !w->unredir_if_possible_excluded)
@@ -1316,7 +1316,7 @@ win_paint_shadow(session_t *ps, win *w,
render(ps, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height, w->shadow_opacity, true, false,
- w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg);
+ w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg, NULL);
}
/**
@@ -1472,7 +1472,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
// Minimize the region we try to blur, if the window itself is not
// opaque, only the frame is.
XserverRegion reg_noframe = None;
- if (WMODE_SOLID == w->mode) {
+ if (win_is_solid(ps, w)) {
XserverRegion reg_all = border_size(ps, w, false);
reg_noframe = win_get_region_noframe(ps, w, false);
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
@@ -1496,10 +1496,14 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
}
static void
-render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
+render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex,
- XserverRegion reg_paint, const reg_data_t *pcache_reg) {
+ XserverRegion reg_paint, const reg_data_t *pcache_reg
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ , const glx_prog_main_t *pprogram
+#endif
+ ) {
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID:
@@ -1515,7 +1519,7 @@ render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
glx_render(ps, ptex, x, y, dx, dy, wid, hei,
- ps->glx_z, opacity, neg, reg_paint, pcache_reg);
+ ps->glx_z, opacity, argb, neg, reg_paint, pcache_reg, pprogram);
ps->glx_z += 1;
break;
#endif
@@ -1911,7 +1915,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
if (!is_region_empty(ps, reg_paint, &cache_reg)) {
set_tgt_clip(ps, reg_paint, &cache_reg);
// Blur window background
- if (w->blur_background && (WMODE_SOLID != w->mode
+ if (w->blur_background && (!win_is_solid(ps, w)
|| (ps->o.blur_background_frame && w->frame_opacity))) {
win_blur_background(ps, w, ps->tgt_buffer.pict, reg_paint, &cache_reg);
}
@@ -1992,7 +1996,8 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
glFlush();
glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0,
- ps->root_width, ps->root_height, 0, 1.0, false, region_real, NULL);
+ ps->root_width, ps->root_height, 0, 1.0, false, false,
+ region_real, NULL, NULL);
// No break here!
case BKEND_GLX:
if (ps->o.glx_use_copysubbuffermesa)
@@ -2396,6 +2401,12 @@ win_determine_fade(session_t *ps, win *w) {
w->fade = w->fade_force;
else if (ps->o.no_fading_openclose && w->in_openclose)
w->fade = false;
+ else if (ps->o.no_fading_destroyed_argb && w->destroyed
+ && WMODE_ARGB == w->mode && w->client_win && w->client_win != w->id) {
+ w->fade = false;
+ // Prevent it from being overwritten by last-paint value
+ w->fade_last = false;
+ }
// Ignore other possible causes of fading state changes after window
// gets unmapped
else if (IsViewable != w->a.map_state) {
@@ -2548,8 +2559,8 @@ win_set_blur_background(session_t *ps, win *w, bool blur_background_new) {
// Only consider window damaged if it's previously painted with background
// blurred
- if ((WMODE_SOLID != w->mode
- || (ps->o.blur_background_frame && w->frame_opacity)))
+ if (!win_is_solid(ps, w)
+ || (ps->o.blur_background_frame && w->frame_opacity))
add_damage_win(ps, w);
}
@@ -3206,6 +3217,9 @@ destroy_win(session_t *ps, Window id) {
w->destroyed = true;
+ if (ps->o.no_fading_destroyed_argb)
+ win_determine_fade(ps, w);
+
// Set fading callback
set_fade_callback(ps, w, destroy_callback, false);
@@ -4482,6 +4496,9 @@ usage(int ret) {
" Mark windows that have no WM frame as active.\n"
"--no-fading-openclose\n"
" Do not fade on window open/close.\n"
+ "--no-fading-destroyed-argb\n"
+ " Do not fade destroyed ARGB windows with WM frame. Workaround of bugs\n"
+ " in Openbox, Fluxbox, etc.\n"
"--shadow-ignore-shaped\n"
" Do not paint shadows on shaped windows. (Deprecated, use\n"
" --shadow-exclude \'bounding_shaped\' or\n"
@@ -4674,6 +4691,12 @@ usage(int ret) {
#else
#define WARNING
#endif
+ "--glx-fshader-win shader\n"
+ " GLX backend: Use specified GLSL fragment shader for rendering window\n"
+ " contents.\n"
+ "--force-win-blend\n"
+ " Force all windows to be painted with blending. Useful if you have a\n"
+ " --glx-fshader-win that could turn opaque pixels transparent.\n"
"--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
" man page for more details." WARNING "\n"
@@ -5367,6 +5390,9 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
wintype_arr_enable(ps->o.wintype_fade);
// --no-fading-open-close
lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose);
+ // --no-fading-destroyed-argb
+ lcfg_lookup_bool(&cfg, "no-fading-destroyed-argb",
+ &ps->o.no_fading_destroyed_argb);
// --shadow-red
config_lookup_float(&cfg, "shadow-red", &ps->o.shadow_red);
// --shadow-green
@@ -5583,6 +5609,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "xrender-sync", no_argument, NULL, 312 },
{ "xrender-sync-fence", no_argument, NULL, 313 },
{ "show-all-xerrors", no_argument, NULL, 314 },
+ { "no-fading-destroyed-argb", no_argument, NULL, 315 },
+ { "force-win-blend", no_argument, NULL, 316 },
+ { "glx-fshader-win", required_argument, NULL, 317 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
@@ -5838,6 +5867,11 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
P_CASEBOOL(311, vsync_use_glfinish);
P_CASEBOOL(312, xrender_sync);
P_CASEBOOL(313, xrender_sync_fence);
+ P_CASEBOOL(315, no_fading_destroyed_argb);
+ P_CASEBOOL(316, force_win_blend);
+ case 317:
+ ps->o.glx_fshader_win_str = mstrcpy(optarg);
+ break;
default:
usage(1);
break;
@@ -6776,6 +6810,9 @@ session_init(session_t *ps_old, int argc, char **argv) {
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
.glx_copy_from_front = false,
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ .glx_prog_win = GLX_PROG_MAIN_INIT,
+#endif
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,
.fork_after_register = false,
@@ -6818,6 +6855,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
.fade_out_step = 0.03 * OPAQUE,
.fade_delta = 10,
.no_fading_openclose = false,
+ .no_fading_destroyed_argb = false,
.fade_blacklist = NULL,
.wintype_opacity = { 0.0 },
@@ -7146,6 +7184,17 @@ session_init(session_t *ps_old, int argc, char **argv) {
#endif
}
+ // Initialize window GL shader
+ if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) {
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ if (!glx_load_prog_main(ps, NULL, ps->o.glx_fshader_win_str, &ps->o.glx_prog_win))
+ exit(1);
+#else
+ printf_errf("(): GLSL supported not compiled in, can't load shader.");
+ exit(1);
+#endif
+ }
+
// Initialize software optimization
if (ps->o.sw_opti)
ps->o.sw_opti = swopti_init(ps);
@@ -7227,7 +7276,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
cxfree(children);
}
-
if (ps->o.track_focus) {
recheck_focus(ps);
}
@@ -7395,6 +7443,7 @@ session_destroy(session_t *ps) {
free(ps->pfds_read);
free(ps->pfds_write);
free(ps->pfds_except);
+ free(ps->o.glx_fshader_win_str);
free_xinerama_info(ps);
#ifdef CONFIG_VSYNC_OPENGL
diff --git a/compton.h b/compton.h
index 7eff0a390..524e81ed9 100644
--- a/compton.h
+++ b/compton.h
@@ -675,20 +675,37 @@ static win *
paint_preprocess(session_t *ps, win *list);
static void
-render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
+render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex,
- XserverRegion reg_paint, const reg_data_t *pcache_reg);
+ XserverRegion reg_paint, const reg_data_t *pcache_reg
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ , const glx_prog_main_t *pprogram
+#endif
+ );
+
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+#define \
+ render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram) \
+ render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram)
+#else
+#define \
+ render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram) \
+ render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg)
+#endif
static inline void
-win_render(session_t *ps, win *w, int x, int y, int wid, int hei, double opacity, XserverRegion reg_paint, const reg_data_t *pcache_reg, Picture pict) {
+win_render(session_t *ps, win *w, int x, int y, int wid, int hei,
+ double opacity, XserverRegion reg_paint, const reg_data_t *pcache_reg,
+ Picture pict) {
const int dx = (w ? w->a.x: 0) + x;
const int dy = (w ? w->a.y: 0) + y;
- const bool argb = (w && w->mode == WMODE_ARGB);
+ const bool argb = (w && (WMODE_ARGB == w->mode || ps->o.force_win_blend));
const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg,
- pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex), reg_paint, pcache_reg);
+ pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex),
+ reg_paint, pcache_reg, (w ? &ps->o.glx_prog_win: NULL));
}
static inline void
diff --git a/opengl.c b/opengl.c
index 951d8e50a..424407f9f 100644
--- a/opengl.c
+++ b/opengl.c
@@ -259,6 +259,23 @@ glx_init_end:
return success;
}
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+
+static void
+glx_free_prog_main(session_t *ps, glx_prog_main_t *pprogram) {
+ if (!pprogram)
+ return;
+ if (pprogram->prog) {
+ glDeleteProgram(pprogram->prog);
+ pprogram->prog = 0;
+ }
+ pprogram->unifm_opacity = -1;
+ pprogram->unifm_invert_color = -1;
+ pprogram->unifm_tex = -1;
+}
+
+#endif
+
/**
* Destroy GLX related resources.
*/
@@ -273,6 +290,10 @@ glx_destroy(session_t *ps) {
if (ppass->prog)
glDeleteProgram(ppass->prog);
}
+
+ glx_free_prog_main(ps, &ps->o.glx_prog_win);
+
+ glx_check_err(ps);
#endif
// Free FBConfigs
@@ -439,6 +460,7 @@ glx_init_blur(session_t *ps) {
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);
@@ -458,6 +480,43 @@ glx_init_blur(session_t *ps) {
#endif
}
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+
+/**
+ * Load a GLSL main program from shader strings.
+ */
+bool
+glx_load_prog_main(session_t *ps,
+ const char *vshader_str, const char *fshader_str,
+ glx_prog_main_t *pprogram) {
+ assert(pprogram);
+
+ // Build program
+ pprogram->prog = glx_create_program_from_str(vshader_str, fshader_str);
+ if (!pprogram->prog) {
+ printf_errf("(): Failed to create GLSL program.");
+ return false;
+ }
+
+ // Get uniform addresses
+#define P_GET_UNIFM_LOC(name, target) { \
+ pprogram->target = glGetUniformLocation(pprogram->prog, name); \
+ if (pprogram->target < 0) { \
+ printf_errf("(): Failed to get location of uniform '" name "'. Might be troublesome."); \
+ } \
+ }
+ P_GET_UNIFM_LOC("opacity", unifm_opacity);
+ P_GET_UNIFM_LOC("invert_color", unifm_invert_color);
+ P_GET_UNIFM_LOC("tex", unifm_tex);
+#undef P_GET_UNIFM_LOC
+
+ glx_check_err(ps);
+
+ return true;
+}
+
+#endif
+
/**
* @brief Update the FBConfig of given depth.
*/
@@ -1314,10 +1373,14 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
* @brief Render a region with texture data.
*/
bool
-glx_render(session_t *ps, const glx_texture_t *ptex,
+glx_render_(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z,
- double opacity, bool neg,
- XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
+ double opacity, bool argb, bool neg,
+ XserverRegion reg_tgt, const reg_data_t *pcache_reg
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ , const glx_prog_main_t *pprogram
+#endif
+ ) {
if (!ptex || !ptex->texture) {
printf_errf("(): Missing texture.");
return false;
@@ -1328,8 +1391,11 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
return true;
#endif
- const bool argb = (GLX_TEXTURE_FORMAT_RGBA_EXT ==
- ps->glx_fbconfigs[ptex->depth]->texture_fmt);
+ argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
+ ps->glx_fbconfigs[ptex->depth]->texture_fmt);
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ const bool has_prog = pprogram && pprogram->prog;
+#endif
bool dual_texture = false;
// It's required by legacy versions of OpenGL to enable texture target
@@ -1350,77 +1416,96 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glColor4f(opacity, opacity, opacity, opacity);
}
- // Color negation
- if (neg) {
- // Simple color negation
- if (!glIsEnabled(GL_BLEND)) {
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_COPY_INVERTED);
- }
- // ARGB texture color negation
- else if (argb) {
- dual_texture = true;
-
- // Use two texture stages because the calculation is too complicated,
- // thanks to madsy for providing code
- // Texture stage 0
- glActiveTexture(GL_TEXTURE0);
-
- // Negation for premultiplied color: color = A - C
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-
- // Pass texture alpha through
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
-
- // Texture stage 1
- glActiveTexture(GL_TEXTURE1);
- glEnable(ptex->target);
- glBindTexture(ptex->target, ptex->texture);
-
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-
- // Modulation with constant factor
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
-
- // Modulation with constant factor
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
-
- glActiveTexture(GL_TEXTURE0);
- }
- // RGB blend color negation
- else {
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-
- // Modulation with constant factor
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-
- // Modulation with constant factor
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ if (!has_prog)
+#endif
+ {
+ // The default, fixed-function path
+ // Color negation
+ if (neg) {
+ // Simple color negation
+ if (!glIsEnabled(GL_BLEND)) {
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(GL_COPY_INVERTED);
+ }
+ // ARGB texture color negation
+ else if (argb) {
+ dual_texture = true;
+
+ // Use two texture stages because the calculation is too complicated,
+ // thanks to madsy for providing code
+ // Texture stage 0
+ glActiveTexture(GL_TEXTURE0);
+
+ // Negation for premultiplied color: color = A - C
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ // Pass texture alpha through
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ // Texture stage 1
+ glActiveTexture(GL_TEXTURE1);
+ glEnable(ptex->target);
+ glBindTexture(ptex->target, ptex->texture);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ // Modulation with constant factor
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
+
+ // Modulation with constant factor
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ glActiveTexture(GL_TEXTURE0);
+ }
+ // RGB blend color negation
+ else {
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ // Modulation with constant factor
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ // Modulation with constant factor
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
}
}
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ else {
+ // Programmable path
+ assert(pprogram->prog);
+ glUseProgram(pprogram->prog);
+ if (pprogram->unifm_opacity >= 0)
+ glUniform1f(pprogram->unifm_opacity, opacity);
+ if (pprogram->unifm_invert_color >= 0)
+ glUniform1i(pprogram->unifm_invert_color, neg);
+ if (pprogram->unifm_tex >= 0)
+ glUniform1i(pprogram->unifm_tex, 0);
+ }
+#endif
#ifdef DEBUG_GLX
printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n", x, y, width, height, dx, dy, ptex->width, ptex->height, z);
@@ -1503,6 +1588,11 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glActiveTexture(GL_TEXTURE0);
}
+#ifdef CONFIG_VSYNC_OPENGL_GLSL
+ if (has_prog)
+ glUseProgram(0);
+#endif
+
glx_check_err(ps);
return true;
@@ -1625,7 +1715,7 @@ glx_create_shader(GLenum shader_type, const char *shader_str) {
bool success = false;
GLuint shader = glCreateShader(shader_type);
if (!shader) {
- printf_errf("(): Failed to create shader with type %d.", shader_type);
+ printf_errf("(): Failed to create shader with type %#x.", shader_type);
goto glx_create_shader_end;
}
glShaderSource(shader, 1, &shader_str, NULL);
@@ -1701,5 +1791,40 @@ glx_create_program_end:
return program;
}
+
+/**
+ * @brief Create a program from vertex and fragment shader strings.
+ */
+GLuint
+glx_create_program_from_str(const char *vert_shader_str,
+ const char *frag_shader_str) {
+ GLuint vert_shader = 0;
+ GLuint frag_shader = 0;
+ GLuint prog = 0;
+
+ if (vert_shader_str)
+ vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
+ if (frag_shader_str)
+ frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
+
+ {
+ GLuint shaders[2];
+ int count = 0;
+ if (vert_shader)
+ shaders[count++] = vert_shader;
+ if (frag_shader)
+ shaders[count++] = frag_shader;
+ assert(count <= sizeof(shaders) / sizeof(shaders[0]));
+ if (count)
+ prog = glx_create_program(shaders, count);
+ }
+
+ if (vert_shader)
+ glDeleteShader(vert_shader);
+ if (frag_shader)
+ glDeleteShader(frag_shader);
+
+ return prog;
+}
#endif