Merge branch 'yshui:next' into next

This commit is contained in:
Arda Atci
2022-12-05 21:07:53 +03:00
committed by GitHub
14 changed files with 202 additions and 117 deletions

View File

@@ -259,10 +259,10 @@ bool gl_dual_kawase_blur(double opacity, struct gl_blur_context *bctx, const rec
return true;
}
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask,
coord_t mask_dst, const region_t *reg_blur,
const region_t *reg_visible attr_unused, GLuint source_texture,
geometry_t source_size, GLuint target_fbo, GLuint default_mask) {
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask, coord_t mask_dst,
const region_t *reg_blur, const region_t *reg_visible attr_unused,
GLuint source_texture, geometry_t source_size, GLuint target_fbo,
GLuint default_mask, bool high_precision) {
bool ret = false;
if (source_size.width != bctx->fb_width || source_size.height != bctx->fb_height) {
@@ -284,7 +284,11 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask,
}
glBindTexture(GL_TEXTURE_2D, bctx->blur_textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_size->width,
GLint format = GL_RGBA8;
if (high_precision) {
format = GL_RGBA16;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, tex_size->width,
tex_size->height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
if (bctx->method == BLUR_METHOD_DUAL_KAWASE) {
@@ -406,7 +410,7 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, void *mask, coord_t mas
return gl_blur_impl(opacity, bctx, mask, mask_dst, reg_blur, reg_visible,
gd->back_texture,
(geometry_t){.width = gd->width, .height = gd->height},
gd->back_fbo, gd->default_mask_texture);
gd->back_fbo, gd->default_mask_texture, gd->dithered_present);
}
static inline void gl_free_blur_shader(gl_blur_shader_t *shader) {

View File

@@ -633,7 +633,7 @@ void gl_resize(struct gl_data *gd, int width, int height) {
assert(viewport_dimensions[1] >= gd->height);
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR,
glTexImage2D(GL_TEXTURE_2D, 0, gd->back_format, width, height, 0, GL_BGR,
GL_UNSIGNED_BYTE, NULL);
gl_check_err();
@@ -879,7 +879,16 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
glUseProgram(0);
gd->present_prog = gl_create_program_from_str(present_vertex_shader, dummy_frag);
gd->dithered_present = ps->o.dithered_present;
if (gd->dithered_present) {
gd->present_prog = gl_create_program_from_strv(
(const char *[]){present_vertex_shader, NULL},
(const char *[]){present_frag, dither_glsl, NULL});
} else {
gd->present_prog = gl_create_program_from_strv(
(const char *[]){present_vertex_shader, NULL},
(const char *[]){dummy_frag, NULL});
}
if (!gd->present_prog) {
log_error("Failed to create the present shader");
return false;
@@ -913,14 +922,23 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
glUseProgram(0);
// Set up the size of the back texture
gl_resize(gd, ps->root_width, ps->root_height);
// Set up the size and format of the back texture
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gd->back_fbo);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
gd->back_texture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
if (!gl_check_fb_complete(GL_FRAMEBUFFER)) {
const GLint *format = gd->dithered_present ? (const GLint[]){GL_RGB16, GL_RGBA16}
: (const GLint[]){GL_RGB8, GL_RGBA8};
for (int i = 0; i < 2; i++) {
gd->back_format = format[i];
gl_resize(gd, ps->root_width, ps->root_height);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, gd->back_texture, 0);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
log_info("Using back buffer format %#x", gd->back_format);
break;
}
}
if (!gl_check_fb_complete(GL_DRAW_FRAMEBUFFER)) {
return false;
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
@@ -1285,7 +1303,7 @@ void *gl_shadow_from_mask(backend_t *base, void *mask,
1.0, gsctx->blur_context, NULL, (coord_t){0}, &reg_blur, NULL,
source_texture,
(geometry_t){.width = new_inner->width, .height = new_inner->height},
fbo, gd->default_mask_texture);
fbo, gd->default_mask_texture, gd->dithered_present);
pixman_region32_fini(&reg_blur);
}

View File

@@ -107,8 +107,11 @@ struct gl_data {
gl_fill_shader_t fill_shader;
gl_shadow_shader_t shadow_shader;
GLuint back_texture, back_fbo;
GLint back_format;
GLuint present_prog;
bool dithered_present;
GLuint default_mask_texture;
/// Called when an gl_texture is decoupled from the texture it refers. Returns
@@ -163,10 +166,10 @@ void *gl_clone(backend_t *base, const void *image_data, const region_t *reg_visi
bool gl_blur(backend_t *base, double opacity, void *ctx, void *mask, coord_t mask_dst,
const region_t *reg_blur, const region_t *reg_visible);
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask,
coord_t mask_dst, const region_t *reg_blur,
const region_t *reg_visible attr_unused, GLuint source_texture,
geometry_t source_size, GLuint target_fbo, GLuint default_mask);
bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask, coord_t mask_dst,
const region_t *reg_blur, const region_t *reg_visible attr_unused,
GLuint source_texture, geometry_t source_size, GLuint target_fbo,
GLuint default_mask, bool high_precision);
void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
void gl_destroy_blur_context(backend_t *base, void *ctx);
struct backend_shadow_context *gl_create_shadow_context(backend_t *base, double radius);
@@ -288,5 +291,6 @@ static const GLuint vert_in_texcoord_loc = 1;
#define QUOTE(...) #__VA_ARGS__
extern const char vertex_shader[], copy_with_mask_frag[], masking_glsl[], dummy_frag[],
fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[], win_shader_glsl[],
win_shader_default[], present_vertex_shader[], shadow_colorization_frag[];
present_frag[], fill_frag[], fill_vert[], interpolating_frag[], interpolating_vert[],
win_shader_glsl[], win_shader_default[], present_vertex_shader[], dither_glsl[],
shadow_colorization_frag[];

View File

@@ -9,6 +9,15 @@ const char dummy_frag[] = GLSL(330,
}
);
const char present_frag[] = GLSL(330,
uniform sampler2D tex;
in vec2 texcoord;
vec4 dither(vec4, vec2);
void main() {
gl_FragColor = dither(texelFetch(tex, ivec2(texcoord.xy), 0), texcoord);
}
);
const char copy_with_mask_frag[] = GLSL(330,
uniform sampler2D tex;
in vec2 texcoord;
@@ -174,6 +183,29 @@ const char vertex_shader[] = GLSL(330,
texcoord = in_texcoord + texorig;
}
);
const char dither_glsl[] = GLSL(330,
// Stolen from: https://www.shadertoy.com/view/7sfXDn
float bayer2(vec2 a) {
a = floor(a);
return fract(a.x / 2. + a.y * a.y * .75);
}
// 16 * 16 is 2^8, so in total we have equivalent of 16-bit
// color depth, should be enough?
float bayer(vec2 a16) {
vec2 a8 = a16 * .5;
vec2 a4 = a8 * .5;
vec2 a2 = a4 * .5;
float bayer32 = ((bayer2(a2) * .25 + bayer2( a4))
* .25 + bayer2( a8))
* .25 + bayer2(a16);
return bayer32;
}
vec4 dither(vec4 c, vec2 coord) {
vec4 residual = mod(c, 1.0 / 255.0);
vec4 dithered = vec4(greaterThan(residual, vec4(1e-4)));
return vec4(c + dithered * bayer(coord) / 255.0);
}
);
const char shadow_colorization_frag[] = GLSL(330,
uniform vec4 color;
uniform sampler2D tex;

View File

@@ -858,6 +858,10 @@ static void get_blur_size(void *blur_context, int *width, int *height) {
}
static backend_t *backend_xrender_init(session_t *ps) {
if (ps->o.dithered_present) {
log_warn("\"dithered-present\" is not supported by the xrender backend.");
}
auto xd = ccalloc(1, struct _xrender_data);
init_backend_base(&xd->base, ps);

155
src/c2.c
View File

@@ -17,15 +17,8 @@
// libpcre
#ifdef CONFIG_REGEX_PCRE
#include <pcre.h>
// For compatibility with <libpcre-8.20
#ifndef PCRE_STUDY_JIT_COMPILE
#define PCRE_STUDY_JIT_COMPILE 0
#define LPCRE_FREE_STUDY(extra) pcre_free(extra)
#else
#define LPCRE_FREE_STUDY(extra) pcre_free_study(extra)
#endif
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#endif
@@ -89,49 +82,52 @@ struct _c2_b {
/// Structure for leaf element in a window condition
struct _c2_l {
bool neg : 1;
enum { C2_L_OEXISTS,
C2_L_OEQ,
C2_L_OGT,
C2_L_OGTEQ,
C2_L_OLT,
C2_L_OLTEQ,
enum {
C2_L_OEXISTS,
C2_L_OEQ,
C2_L_OGT,
C2_L_OGTEQ,
C2_L_OLT,
C2_L_OLTEQ,
} op : 3;
enum { C2_L_MEXACT,
C2_L_MSTART,
C2_L_MCONTAINS,
C2_L_MWILDCARD,
C2_L_MPCRE,
enum {
C2_L_MEXACT,
C2_L_MSTART,
C2_L_MCONTAINS,
C2_L_MWILDCARD,
C2_L_MPCRE,
} match : 3;
bool match_ignorecase : 1;
char *tgt;
xcb_atom_t tgtatom;
bool tgt_onframe;
int index;
enum { C2_L_PUNDEFINED = -1,
C2_L_PID = 0,
C2_L_PX,
C2_L_PY,
C2_L_PX2,
C2_L_PY2,
C2_L_PWIDTH,
C2_L_PHEIGHT,
C2_L_PWIDTHB,
C2_L_PHEIGHTB,
C2_L_PBDW,
C2_L_PFULLSCREEN,
C2_L_POVREDIR,
C2_L_PARGB,
C2_L_PFOCUSED,
C2_L_PWMWIN,
C2_L_PBSHAPED,
C2_L_PROUNDED,
C2_L_PCLIENT,
C2_L_PWINDOWTYPE,
C2_L_PLEADER,
C2_L_PNAME,
C2_L_PCLASSG,
C2_L_PCLASSI,
C2_L_PROLE,
enum {
C2_L_PUNDEFINED = -1,
C2_L_PID = 0,
C2_L_PX,
C2_L_PY,
C2_L_PX2,
C2_L_PY2,
C2_L_PWIDTH,
C2_L_PHEIGHT,
C2_L_PWIDTHB,
C2_L_PHEIGHTB,
C2_L_PBDW,
C2_L_PFULLSCREEN,
C2_L_POVREDIR,
C2_L_PARGB,
C2_L_PFOCUSED,
C2_L_PWMWIN,
C2_L_PBSHAPED,
C2_L_PROUNDED,
C2_L_PCLIENT,
C2_L_PWINDOWTYPE,
C2_L_PLEADER,
C2_L_PNAME,
C2_L_PCLASSG,
C2_L_PCLASSI,
C2_L_PROLE,
} predef;
enum c2_l_type {
C2_L_TUNDEFINED,
@@ -142,15 +138,16 @@ struct _c2_l {
C2_L_TDRAWABLE,
} type;
int format;
enum { C2_L_PTUNDEFINED,
C2_L_PTSTRING,
C2_L_PTINT,
enum {
C2_L_PTUNDEFINED,
C2_L_PTSTRING,
C2_L_PTINT,
} ptntype;
char *ptnstr;
long ptnint;
#ifdef CONFIG_REGEX_PCRE
pcre *regex_pcre;
pcre_extra *regex_pcre_extra;
pcre2_code *regex_pcre;
pcre2_match_data *regex_pcre_match;
#endif
};
@@ -1059,32 +1056,31 @@ static bool c2_l_postprocess(session_t *ps, c2_l_t *pleaf) {
// PCRE patterns
if (C2_L_PTSTRING == pleaf->ptntype && C2_L_MPCRE == pleaf->match) {
#ifdef CONFIG_REGEX_PCRE
const char *error = NULL;
int erroffset = 0;
int options = 0;
int errorcode = 0;
PCRE2_SIZE erroffset = 0;
unsigned int options = 0;
// Ignore case flag
if (pleaf->match_ignorecase)
options |= PCRE_CASELESS;
if (pleaf->match_ignorecase) {
options |= PCRE2_CASELESS;
}
// Compile PCRE expression
pleaf->regex_pcre =
pcre_compile(pleaf->ptnstr, options, &error, &erroffset, NULL);
if (!pleaf->regex_pcre) {
log_error("Pattern \"%s\": PCRE regular expression parsing "
pcre2_compile((PCRE2_SPTR)pleaf->ptnstr, PCRE2_ZERO_TERMINATED,
options, &errorcode, &erroffset, NULL);
if (pleaf->regex_pcre == NULL) {
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
log_error("Pattern \"%s\": PCRE regular expression "
"parsing "
"failed on "
"offset %d: %s",
pleaf->ptnstr, erroffset, error);
"offset %zu: %s",
pleaf->ptnstr, erroffset, buffer);
return false;
}
#ifdef CONFIG_REGEX_PCRE_JIT
pleaf->regex_pcre_extra =
pcre_study(pleaf->regex_pcre, PCRE_STUDY_JIT_COMPILE, &error);
if (!pleaf->regex_pcre_extra) {
printf("Pattern \"%s\": PCRE regular expression study failed: %s",
pleaf->ptnstr, error);
}
#endif
pleaf->regex_pcre_match =
pcre2_match_data_create_from_pattern(pleaf->regex_pcre, NULL);
// Free the target string
// free(pleaf->tgt);
@@ -1102,16 +1098,18 @@ static bool c2_tree_postprocess(session_t *ps, c2_ptr_t node) {
if (!node.isbranch) {
return c2_l_postprocess(ps, node.l);
}
if (!c2_tree_postprocess(ps, node.b->opr1))
if (!c2_tree_postprocess(ps, node.b->opr1)) {
return false;
}
return c2_tree_postprocess(ps, node.b->opr2);
}
bool c2_list_postprocess(session_t *ps, c2_lptr_t *list) {
c2_lptr_t *head = list;
while (head) {
if (!c2_tree_postprocess(ps, head->ptr))
if (!c2_tree_postprocess(ps, head->ptr)) {
return false;
}
head = head->next;
}
return true;
@@ -1124,8 +1122,9 @@ static void c2_free(c2_ptr_t p) {
if (p.isbranch) {
c2_b_t *const pbranch = p.b;
if (!pbranch)
if (!pbranch) {
return;
}
c2_free(pbranch->opr1);
c2_free(pbranch->opr2);
@@ -1135,14 +1134,15 @@ static void c2_free(c2_ptr_t p) {
else {
c2_l_t *const pleaf = p.l;
if (!pleaf)
if (!pleaf) {
return;
}
free(pleaf->tgt);
free(pleaf->ptnstr);
#ifdef CONFIG_REGEX_PCRE
pcre_free(pleaf->regex_pcre);
LPCRE_FREE_STUDY(pleaf->regex_pcre_extra);
pcre2_code_free(pleaf->regex_pcre);
pcre2_match_data_free(pleaf->regex_pcre_match);
#endif
free(pleaf);
}
@@ -1550,9 +1550,10 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
case C2_L_MPCRE:
#ifdef CONFIG_REGEX_PCRE
assert(strlen(tgt) <= INT_MAX);
res = (pcre_exec(pleaf->regex_pcre,
pleaf->regex_pcre_extra, tgt,
(int)strlen(tgt), 0, 0, NULL, 0) >= 0);
assert(pleaf->regex_pcre);
res = (pcre2_match(pleaf->regex_pcre, (PCRE2_SPTR)tgt,
strlen(tgt), 0, 0,
pleaf->regex_pcre_match, NULL) > 0);
#else
assert(0);
#endif

View File

@@ -310,6 +310,8 @@ typedef struct options {
/// A list of conditions of windows to which transparent clipping
/// should not apply
c2_lptr_t *transparent_clipping_blacklist;
bool dithered_present;
} options_t;
extern const char *const BACKEND_STRS[NUM_BKEND + 1];

View File

@@ -461,6 +461,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
lcfg_lookup_bool(&cfg, "no-ewmh-fullscreen", &opt->no_ewmh_fullscreen);
// --transparent-clipping
lcfg_lookup_bool(&cfg, "transparent-clipping", &opt->transparent_clipping);
// --dithered_present
lcfg_lookup_bool(&cfg, "dithered-present", &opt->dithered_present);
// --transparent-clipping-exclude
parse_cfg_condlst(&cfg, &opt->transparent_clipping_blacklist,
"transparent-clipping-exclude");

View File

@@ -44,11 +44,8 @@ if get_option('config_file')
srcs += [ 'config_libconfig.c' ]
endif
if get_option('regex')
pcre = dependency('libpcre', required: true)
pcre = dependency('libpcre2-8', required: true)
cflags += ['-DCONFIG_REGEX_PCRE']
if pcre.version().version_compare('>=8.20')
cflags += ['-DCONFIG_REGEX_PCRE_JIT']
endif
deps += [pcre]
endif

View File

@@ -46,7 +46,7 @@ static const struct picom_option picom_options[] = {
{"fade-delta" , required_argument, 'D', NULL , "The time between steps in a fade in milliseconds. (default 10)"},
{"menu-opacity" , required_argument, 'm', NULL , "The opacity for menus. (default 1.0)"},
{"shadow" , no_argument , 'c', NULL , "Enabled client-side shadows on windows."},
{"clear-shadow" , no_argument , 'z', NULL , "Don't dreaw shadow behind the window."},
{"clear-shadow" , no_argument , 'z', NULL , "Don't draw shadow behind the window."},
{"fading" , no_argument , 'f', NULL , "Fade windows in/out when opening/closing and when opacity changes, "
"unless --no-fading-openclose is used."},
{"inactive-opacity" , required_argument, 'i', NULL , "Opacity of inactive windows. (0.1 - 1.0)"},
@@ -168,6 +168,10 @@ static const struct picom_option picom_options[] = {
"similar to --opacity-rule. SHADER_PATH can be \"default\", in which case "
"the default shader will be used. Does not work when --legacy-backends is "
"enabled. See man page for more details"},
// 338 is transparent-clipping-exclude
{"dithered-present" , no_argument , 339, NULL , "Use higher precision during rendering, and apply dither when presenting the "
"rendered screen. Reduces banding artifacts, but might cause performance "
"degradation. Only works with OpenGL."},
{"legacy-backends" , no_argument , 733, NULL , "Use deprecated version of the backends."},
{"monitor-repaint" , no_argument , 800, NULL , "Highlight the updated area of the screen. For debugging."},
{"diagnostics" , no_argument , 801, NULL , "Print diagnostic information"},
@@ -725,6 +729,10 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
// --clip-shadow-above
condlst_add(&opt->shadow_clip_list, optarg);
break;
case 339:
// --dithered-present
opt->dithered_present = true;
break;
P_CASEBOOL(733, legacy_backends);
P_CASEBOOL(800, monitor_repaint);
case 801:

View File

@@ -357,7 +357,7 @@ bool win_bind_mask(struct backend_base *b, struct managed_win *w) {
auto reg_bound_local = win_get_bounding_shape_global_by_val(w);
pixman_region32_translate(&reg_bound_local, -w->g.x, -w->g.y);
w->mask_image = b->ops->make_mask(
b, (geometry_t){.width = w->g.width, .height = w->g.height}, &reg_bound_local);
b, (geometry_t){.width = w->widthb, .height = w->heightb}, &reg_bound_local);
pixman_region32_fini(&reg_bound_local);
if (!w->mask_image) {