diff --git a/Makefile b/Makefile index d3b004e..2f0461e 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ obj = $(src:.c=.o) # Build type parameter ifeq ($(BUILD),debug) - CFLAGS_BUILD = -O1 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls + CFLAGS_BUILD = -O0 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls GLAD_GEN = c-debug ASAN = -lasan else diff --git a/glx_wcb.c b/glx_wcb.c index 659cca0..69def8e 100644 --- a/glx_wcb.c +++ b/glx_wcb.c @@ -86,7 +86,6 @@ static void* create_and_bind(const char* name, const char* class, XVisualInfo* vi; XSetWindowAttributes attr; - GC gc; GLXFBConfig* fbc; int fb_sz, best = -1, samp = -1; @@ -175,8 +174,6 @@ static void* create_and_bind(const char* name, const char* class, XFree(vi); - gc = XCreateGC(display, w->w, 0, 0); - XStoreName(display, w->w, name); Atom dwin = XInternAtom(display, "WM_DELETE_WINDOW", false); diff --git a/render.c b/render.c index 3a94648..8fcbe17 100644 --- a/render.c +++ b/render.c @@ -85,7 +85,7 @@ struct gl_bind { struct gl_sfbo { GLuint fbo, tex, shader; - bool valid; + bool valid, nativeonly; const char* name; struct gl_bind* binds; size_t binds_sz; @@ -109,7 +109,7 @@ struct gl_data { double tcounter; int fcounter, ucounter, kcounter; bool print_fps, avg_window, interpolate, force_geometry, copy_desktop, - smooth_pass, use_alpha; + smooth_pass, premultiply_alpha; void** t_data; float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio, smooth_factor, fft_scale, fft_cutoff; @@ -165,7 +165,8 @@ static GLuint shaderload(const char* rpath, "#define UNIFORM_LIMIT %d\n" "#define PRE_SMOOTHED_AUDIO %d\n" "#define SMOOTH_FACTOR %.6f\n" - "#define USE_ALPHA %d\n"; + "#define USE_ALPHA %d\n" + "#define PREMULTIPLY_ALPHA %d\n"; struct glsl_ext ext = { .source = raw ? NULL : map, @@ -180,11 +181,11 @@ static GLuint shaderload(const char* rpath, /* If this is raw input, skip processing */ if (!raw) ext_process(&ext, rpath); - size_t blen = strlen(header_fmt) + 42; + size_t blen = strlen(header_fmt) + 64; GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len); int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms, gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor, - gl->use_alpha ? 1 : 0); + 1, gl->premultiply_alpha ? 1 : 0); if (written < 0) { fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path); return 0; @@ -696,35 +697,35 @@ struct renderer* rd_new(const char** paths, const char* entry, struct gl_data* gl = r->gl; *gl = (struct gl_data) { - .w = NULL, - .wcb = NULL, - .stages = NULL, - .rate = 0, - .tcounter = 0.0D, - .fcounter = 0, - .ucounter = 0, - .kcounter = 0, - .fr = 1.0F, - .ur = 1.0F, - .print_fps = true, - .bufscale = 1, - .avg_frames = 6, - .avg_window = true, - .gravity_step = 4.2, - .interpolate = true, - .force_geometry = false, - .smooth_factor = 0.025, - .smooth_distance = 0.01, - .smooth_ratio = 4, - .bg_tex = 0, - .sm_prog = 0, - .copy_desktop = true, - .use_alpha = true, - .smooth_pass = true, - .fft_scale = 10.2F, - .fft_cutoff = 0.3F, - .geometry = { 0, 0, 500, 400 }, - .clear_color = { 0.0F, 0.0F, 0.0F, 0.0F } + .w = NULL, + .wcb = NULL, + .stages = NULL, + .rate = 0, + .tcounter = 0.0D, + .fcounter = 0, + .ucounter = 0, + .kcounter = 0, + .fr = 1.0F, + .ur = 1.0F, + .print_fps = true, + .bufscale = 1, + .avg_frames = 6, + .avg_window = true, + .gravity_step = 4.2, + .interpolate = true, + .force_geometry = false, + .smooth_factor = 0.025, + .smooth_distance = 0.01, + .smooth_ratio = 4, + .bg_tex = 0, + .sm_prog = 0, + .copy_desktop = true, + .premultiply_alpha = true, + .smooth_pass = true, + .fft_scale = 10.2F, + .fft_cutoff = 0.3F, + .geometry = { 0, 0, 500, 400 }, + .clear_color = { 0.0F, 0.0F, 0.0F, 0.0F } }; bool forced = force_backend != NULL; @@ -803,7 +804,7 @@ struct renderer* rd_new(const char** paths, const char* entry, bool native_opacity = !strcmp("native", (char*) args[0]); - gl->use_alpha = true; + gl->premultiply_alpha = native_opacity; gl->wcb->set_transparent(native_opacity); @@ -853,6 +854,17 @@ struct renderer* rd_new(const char** paths, const char* entry, } }) }, + { + .name = "nativeonly", .fmt = "b", + .handler = RHANDLER(name, args, { + if (current) + current->nativeonly = *(bool*) args[0]; + else { + fprintf(stderr, "`nativeonly` request needs module context\n"); + exit(EXIT_FAILURE); + } + }) + }, WINDOW_HINT(floating), WINDOW_HINT(decorated), WINDOW_HINT(focused), @@ -1079,8 +1091,10 @@ struct renderer* rd_new(const char** paths, const char* entry, glDisable(GL_MULTISAMPLE); glDisable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (!gl->premultiply_alpha) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } size_t m_len = strlen(module); size_t bsz = d_len + m_len + 2; @@ -1141,11 +1155,12 @@ struct renderer* rd_new(const char** paths, const char* entry, struct gl_sfbo* s = &stages[idx - 1]; *s = (struct gl_sfbo) { - .name = strdup(d->d_name), - .shader = 0, - .valid = false, - .binds = malloc(1), - .binds_sz = 0 + .name = strdup(d->d_name), + .shader = 0, + .valid = false, + .nativeonly = false, + .binds = malloc(1), + .binds_sz = 0 }; current = s; @@ -1183,6 +1198,23 @@ struct renderer* rd_new(const char** paths, const char* entry, } while (found); } } + + gl->stages = stages; + gl->stages_sz = count; + + { + struct gl_sfbo* final = NULL; + if (!gl->premultiply_alpha) { + for (size_t t = 0; t < gl->stages_sz; ++t) { + if (!gl->stages[t].nativeonly) { + final = &gl->stages[t]; + } + } + } + /* Invalidate framebuffer and use direct rendering if it was instantiated + due to a following `nativeonly` shader pass. */ + if (final) final->valid = false; + } /* Compile smooth pass shader */ @@ -1193,15 +1225,11 @@ struct renderer* rd_new(const char** paths, const char* entry, char util[usz]; /* module pack path to use */ snprintf(util, usz, "%s/%s", data, util_folder); loading_smooth_pass = true; - if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag"))) { + if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag"))) abort(); - } loading_smooth_pass = false; } - gl->stages = stages; - gl->stages_sz = count; - /* target seconds per update */ gl->target_spu = (float) (r->samplesize_request / 4) / (float) r->rate_request; @@ -1337,6 +1365,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi /* Current shader program */ struct gl_sfbo* current = &gl->stages[t]; + + if (current->nativeonly && !gl->premultiply_alpha) + continue; /* Bind framebuffer if this is not the final pass */ if (current->valid) @@ -1377,9 +1408,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi /* We need to disable blending, we might read in bogus alpha values due to how we obtain the background texture (format is four byte `rgb_`, where the last value is skipped) */ - glDisable(GL_BLEND); + if (!gl->premultiply_alpha) glDisable(GL_BLEND); drawoverlay(&gl->overlay); - glEnable(GL_BLEND); + if (!gl->premultiply_alpha) glEnable(GL_BLEND); glUseProgram(0); } @@ -1457,7 +1488,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi /* setup and bind framebuffer to texture */ glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo); - glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, sm->tex, 0); + glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,\ + GL_TEXTURE_1D, sm->tex, 0); switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) { case GL_FRAMEBUFFER_COMPLETE: break; @@ -1478,11 +1510,11 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi glUniform1i(sm_uw, sz); /* target texture width */ glUniform1i(sm_usz, sz); /* source texture width */ glUniform1i(sm_utex, offset); - glDisable(GL_BLEND); + if (!gl->premultiply_alpha) glDisable(GL_BLEND); glViewport(0, 0, sz, 1); drawoverlay(&gl->overlay); glViewport(0, 0, ww, wh); - glEnable(GL_BLEND); + if (!gl->premultiply_alpha) glEnable(GL_BLEND); /* Return state */ glUseProgram(current->shader); diff --git a/shaders/circle.glsl b/shaders/circle.glsl index 6be8473..83b8ad3 100644 --- a/shaders/circle.glsl +++ b/shaders/circle.glsl @@ -1,7 +1,7 @@ /* center radius (pixels) */ #define C_RADIUS 128 /* center line thickness (pixels) */ -#define C_LINE 2 +#define C_LINE 1.5 /* outline color */ #define OUTLINE #333333 /* Amplify magnitude of the results each bar displays */ diff --git a/shaders/circle/3.frag b/shaders/circle/3.frag new file mode 100644 index 0000000..66f7cd9 --- /dev/null +++ b/shaders/circle/3.frag @@ -0,0 +1 @@ +#include ":util/premultiply.frag" diff --git a/shaders/radial/1.frag b/shaders/radial/1.frag index 1952879..c2dddac 100644 --- a/shaders/radial/1.frag +++ b/shaders/radial/1.frag @@ -29,10 +29,10 @@ out vec4 fragment; #define PI 3.14159265359 void main() { - + #if USE_ALPHA > 0 - #define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - f.a), max(c.a, f.a)) - fragment.a; + #define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - clamp(f.a, 0, 1)), max(c.a, f.a)) + fragment = #00000000; #else #define APPLY_FRAG(f, c) f = c #endif diff --git a/shaders/radial/2.frag b/shaders/radial/2.frag new file mode 100644 index 0000000..66f7cd9 --- /dev/null +++ b/shaders/radial/2.frag @@ -0,0 +1 @@ +#include ":util/premultiply.frag" diff --git a/shaders/rc.glsl b/shaders/rc.glsl index f5a31a7..1162d14 100644 --- a/shaders/rc.glsl +++ b/shaders/rc.glsl @@ -28,10 +28,9 @@ /* Set window background opacity mode. Possible values are: - "native" - True transparency provided by the compositor. - Requires GLFW 3.3+ and an active compositor. Can - reduce performance on some systems, and will not - blend with the visualizer's alpha layer. + "native" - True transparency provided by the compositor. Can + reduce performance on some systems, depending on + the compositor used. "xroot" - Maintain a copy of the root window's pixmap (usually the desktop background) to provide a @@ -54,8 +53,8 @@ #request setgeometry 0 0 800 600 /* Window background color (RGB format). - Only works with `setopacity "none"` */ -#request setbg 000000 + Does not work with `setopacity "xroot"` */ +#request setbg 00000000 /* (X11 only) EWMH Window type. Possible values are: @@ -68,7 +67,7 @@ https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#idm140130317606816 */ -#request setxwintype "desktop" +#request setxwintype "normal" /* (X11 only) EWMH Window state atoms (multiple can be specified). Possible values are: diff --git a/shaders/util/premultiply.frag b/shaders/util/premultiply.frag new file mode 100644 index 0000000..ec0e9f9 --- /dev/null +++ b/shaders/util/premultiply.frag @@ -0,0 +1,15 @@ + +#request nativeonly true + +#request uniform "prev" tex +uniform sampler2D tex; + +out vec4 fragment; +in vec4 gl_FragCoord; + +void main() { + fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0); + #if PREMULTIPLY_ALPHA > 0 + fragment.rgb *= fragment.a; + #endif +}