From 43b8b1ddbfab6df8591e34c58387fb7cd3157ea9 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Thu, 29 Aug 2019 02:10:00 +0100 Subject: [PATCH 01/38] Add rounded corners --- man/picom.1.asciidoc | 3 + src/backend/backend.c | 6 +- src/config.h | 3 +- src/config_libconfig.c | 2 + src/event.c | 4 +- src/options.c | 5 ++ src/picom.c | 11 ++-- src/render.c | 121 +++++++++++++++++++++++++++++++++++------ src/render.h | 2 +- src/win.c | 27 +++++++-- src/win.h | 26 +++++++-- src/x.c | 20 +++++++ src/x.h | 9 +++ 13 files changed, 202 insertions(+), 37 deletions(-) diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index b22030b3a8..0308508636 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -106,6 +106,9 @@ OPTIONS *--inactive-dim* 'VALUE':: Dim inactive windows. (0.0 - 1.0, defaults to 0.0) +*--corner-radius* 'VALUE':: + Round the corners of windows. (defaults to 0). + *--mark-wmwin-focused*:: Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active. diff --git a/src/backend/backend.c b/src/backend/backend.c index f03e1ffcd4..bb0af5a9ce 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -168,7 +168,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // The bounding shape of the window, in global/target coordinates // reminder: bounding shape contains the WM frame - auto reg_bound = win_get_bounding_shape_global_by_val(w); + auto reg_bound = win_get_bounding_shape_global_by_val(w, true); // The clip region for the current window, in global/target coordinates // reg_paint_in_bound \in reg_paint @@ -227,7 +227,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { assert(ps->o.blur_background_frame); assert(real_win_mode == WMODE_FRAME_TRANS); - auto reg_blur = win_get_region_frame_local_by_val(w); + auto reg_blur = win_get_region_frame_local_by_val(w, true); pixman_region32_translate(®_blur, w->g.x, w->g.y); // make sure reg_blur \in reg_paint pixman_region32_intersect(®_blur, ®_blur, ®_paint); @@ -357,7 +357,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ®_visible_local, (double[]){dim_opacity}); } if (w->frame_opacity != 1) { - auto reg_frame = win_get_region_frame_local_by_val(w); + auto reg_frame = win_get_region_frame_local_by_val(w, true); ps->backend_data->ops->image_op( ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame, ®_visible_local, (double[]){w->frame_opacity}); diff --git a/src/config.h b/src/config.h index 403ea548bf..faebd930b0 100644 --- a/src/config.h +++ b/src/config.h @@ -23,8 +23,8 @@ #include "kernel.h" #include "log.h" #include "region.h" -#include "win_defs.h" #include "types.h" +#include "win_defs.h" typedef struct session session_t; @@ -239,6 +239,7 @@ typedef struct options { // Make transparent windows clip other windows, instead of blending on top of // them bool transparent_clipping; + int corner_radius; } options_t; extern const char *const BACKEND_STRS[NUM_BKEND + 1]; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 6389aa403a..3c70aa78b4 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -239,6 +239,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad // --active_opacity if (config_lookup_float(&cfg, "active-opacity", &dval)) opt->active_opacity = normalize_d(dval); + // --corner-radius + config_lookup_int(&cfg, "corner-radius", &opt->corner_radius); // -e (frame_opacity) config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); // -c (shadow_enable) diff --git a/src/event.c b/src/event.c index 3a3369d5b9..9f094c0bb5 100644 --- a/src/event.c +++ b/src/event.c @@ -618,14 +618,14 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev) * if we attempt to rebuild border_size */ // Mark the old border_size as damaged - region_t tmp = win_get_bounding_shape_global_by_val(w); + region_t tmp = win_get_bounding_shape_global_by_val(w, true); add_damage(ps, &tmp); pixman_region32_fini(&tmp); win_update_bounding_shape(ps, w); // Mark the new border_size as damaged - tmp = win_get_bounding_shape_global_by_val(w); + tmp = win_get_bounding_shape_global_by_val(w, true); add_damage(ps, &tmp); pixman_region32_fini(&tmp); diff --git a/src/options.c b/src/options.c index 8f44b4336f..17bb7fff28 100644 --- a/src/options.c +++ b/src/options.c @@ -114,6 +114,9 @@ static void usage(const char *argv0, int ret) { "--active-opacity opacity\n" " Default opacity for active windows. (0.0 - 1.0)\n" "\n" + "--corner-radius value\n" + " Round the corners of windows. (defaults to 0)\n" + "\n" "--mark-wmwin-focused\n" " Try to detect WM windows and mark them as active.\n" "\n" @@ -437,6 +440,7 @@ static const struct option longopts[] = { {"blur-method", required_argument, NULL, 328}, {"blur-size", required_argument, NULL, 329}, {"blur-deviation", required_argument, NULL, 330}, + {"corner-radius", required_argument, NULL, 331}, {"experimental-backends", no_argument, NULL, 733}, {"monitor-repaint", no_argument, NULL, 800}, {"diagnostics", no_argument, NULL, 801}, @@ -842,6 +846,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->blur_deviation = atof(optarg); break; + case 331: opt->corner_radius = atoi(optarg); break; P_CASEBOOL(733, experimental_backends); P_CASEBOOL(800, monitor_repaint); case 801: opt->print_diagnostics = true; break; diff --git a/src/picom.c b/src/picom.c index 93d425e31b..e76611f440 100644 --- a/src/picom.c +++ b/src/picom.c @@ -472,6 +472,8 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { w->frame_opacity = 1.0; } + w->corner_radius = ps->o.corner_radius; + // Update window mode w->mode = win_calc_mode(w); @@ -558,11 +560,10 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { ps->o.transparent_clipping) { // w->mode == WMODE_SOLID or WMODE_FRAME_TRANS region_t *tmp = rc_region_new(); - if (w->mode == WMODE_SOLID) { - *tmp = win_get_bounding_shape_global_by_val(w); - } else { - // w->mode == WMODE_FRAME_TRANS - win_get_region_noframe_local(w, tmp); + if (w->frame_opacity == 1) + *tmp = win_get_bounding_shape_global_by_val(w, false); + else { + win_get_region_noframe_local(w, tmp, false); pixman_region32_intersect(tmp, tmp, &w->bounding_shape); pixman_region32_translate(tmp, w->g.x, w->g.y); } diff --git a/src/render.c b/src/render.c index c0e33e339f..476a72a56a 100644 --- a/src/render.c +++ b/src/render.c @@ -186,8 +186,52 @@ void free_paint(session_t *ps, paint_t *ppaint) { ppaint->pixmap = XCB_NONE; } +uint32_t +make_circle(int cx, int cy, int radius, uint32_t max_ntraps, xcb_render_trapezoid_t traps[]) { + uint32_t n = 0, k = 0; + int y1, y2; + double w; + while (k < max_ntraps) { + y1 = (int)(-radius * cos(M_PI * k / max_ntraps)); + traps[n].top = (cy + y1) << 16; + traps[n].left.p1.y = (cy + y1) << 16; + traps[n].right.p1.y = (cy + y1) << 16; + w = sqrt(radius * radius - y1 * y1) * 65536; + traps[n].left.p1.x = (int)((cx << 16) - w); + traps[n].right.p1.x = (int)((cx << 16) + w); + + do { + k++; + y2 = (int)(-radius * cos(M_PI * k / max_ntraps)); + } while (y1 == y2); + + traps[n].bottom = (cy + y2) << 16; + traps[n].left.p2.y = (cy + y2) << 16; + traps[n].right.p2.y = (cy + y2) << 16; + w = sqrt(radius * radius - y2 * y2) * 65536; + traps[n].left.p2.x = (int)((cx << 16) - w); + traps[n].right.p2.x = (int)((cx << 16) + w); + n++; + } + return n; +} + +uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t traps[]) { + traps[0].top = y << 16; + traps[0].left.p1.y = y << 16; + traps[0].left.p1.x = x << 16; + traps[0].left.p2.y = (y + hei) << 16; + traps[0].left.p2.x = x << 16; + traps[0].bottom = (y + hei) << 16; + traps[0].right.p1.x = (x + wid) << 16; + traps[0].right.p1.y = y << 16; + traps[0].right.p2.x = (x + wid) << 16; + traps[0].right.p2.y = (y + hei) << 16; + return 1; +} + void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity, - bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, + bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram) { switch (ps->o.backend) { case BKEND_XRENDER: @@ -195,12 +239,55 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl auto alpha_step = (int)(opacity * MAX_ALPHA); xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step]; if (alpha_step != 0) { - uint8_t op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC - : XCB_RENDER_PICT_OP_OVER); - xcb_render_composite( - ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict, - to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx), - to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); + if (cr) { + xcb_render_picture_t p_tmp = x_create_picture_with_standard( + ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + xcb_render_color_t trans = { + .red = 0, .blue = 0, .green = 0, .alpha = 0}; + const xcb_rectangle_t rect = {.x = 0, + .y = 0, + .width = to_u16_checked(wid), + .height = to_u16_checked(hei)}; + xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, + p_tmp, trans, 1, &rect); + + uint32_t max_ntraps = 15; + xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; + + uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps); + n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n); + n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n); + n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n); + n += make_rectangle(0, cr, cr, hei - 2 * cr, traps + n); + n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n); + n += make_rectangle(wid - cr, cr, cr, hei - 2 * cr, traps + n); + n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n); + n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr, + traps + n); + + xcb_render_trapezoids( + ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, + x_get_pictfmt_for_standard(ps->c, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8 ), + to_i16_checked(cr), 0, n, traps); + + xcb_render_composite( + ps->c, XCB_RENDER_PICT_OP_OVER, p_tmp, alpha_pict, + ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), + 0, 0, to_i16_checked(dx), to_i16_checked(dy), + to_u16_checked(wid), to_u16_checked(hei)); + + xcb_render_free_picture(ps->c, p_tmp); + + } else { + uint8_t op = + ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC + : XCB_RENDER_PICT_OP_OVER); + xcb_render_composite( + ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict, + to_i16_checked(x), to_i16_checked(y), 0, 0, + to_i16_checked(dx), to_i16_checked(dy), + to_u16_checked(wid), to_u16_checked(hei)); + } } break; } @@ -229,8 +316,8 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, const bool argb = (w && (win_has_alpha(w) || 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, + render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w ? w->corner_radius : 0), + pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL w ? &ps->glx_prog_win : NULL #else @@ -613,7 +700,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { } render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, - w->shadow_height, w->shadow_opacity, true, false, w->shadow_paint.pict, + w->shadow_height, w->shadow_opacity, true, false, 0, w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL); } @@ -730,11 +817,11 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t // Minimize the region we try to blur, if the window itself is not // opaque, only the frame is. - region_t reg_blur = win_get_bounding_shape_global_by_val(w); + region_t reg_blur = win_get_bounding_shape_global_by_val(w, false); if (w->mode == WMODE_FRAME_TRANS && !ps->o.force_win_blend) { region_t reg_noframe; pixman_region32_init(®_noframe); - win_get_region_noframe_local(w, ®_noframe); + win_get_region_noframe_local(w, ®_noframe, true); pixman_region32_translate(®_noframe, w->g.x, w->g.y); pixman_region32_subtract(®_blur, ®_blur, ®_noframe); pixman_region32_fini(®_noframe); @@ -851,7 +938,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // // Whether this is beneficial is to be determined XXX for (auto w = t; w; w = w->prev_trans) { - region_t bshape = win_get_bounding_shape_global_by_val(w); + region_t bshape_no_corners = win_get_bounding_shape_global_by_val(w, false); + region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true); // Painting shadow if (w->shadow) { // Lazy shadow building @@ -880,7 +968,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // saving GPU power and handling shaped windows (XXX // unconfirmed) if (!ps->o.wintype_option[w->window_type].full_shadow) - pixman_region32_subtract(®_tmp, ®_tmp, &bshape); + pixman_region32_subtract(®_tmp, ®_tmp, &bshape_no_corners); if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 && w->xinerama_scr < ps->xinerama_nscrs) @@ -907,8 +995,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Remember, reg_ignore is the union of all windows above the current // window. pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); - pixman_region32_intersect(®_tmp, ®_tmp, &bshape); - pixman_region32_fini(&bshape); + pixman_region32_intersect(®_tmp, ®_tmp, &bshape_corners); + pixman_region32_fini(&bshape_corners); + pixman_region32_fini(&bshape_no_corners); if (pixman_region32_not_empty(®_tmp)) { set_tgt_clip(ps, ®_tmp); diff --git a/src/render.h b/src/render.h index 92b71c8e01..545e90844a 100644 --- a/src/render.h +++ b/src/render.h @@ -26,7 +26,7 @@ typedef struct paint { } paint_t; void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity, - bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex, + bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); diff --git a/src/win.c b/src/win.c index 281a153cbc..d0adc6ccb3 100644 --- a/src/win.c +++ b/src/win.c @@ -56,6 +56,17 @@ static const int WIN_GET_LEADER_MAX_RECURSION = 20; static const int ROUNDED_PIXELS = 1; static const double ROUNDED_PERCENT = 0.05; +/// Generate a "return by value" function, from a function that returns the +/// region via a region_t pointer argument. +/// Function signature has to be (win *, region_t *, bool) +#define gen_by_val_corners(fun) \ + region_t fun##_by_val(const struct managed_win *w, bool include_corners) { \ + region_t ret; \ + pixman_region32_init(&ret); \ + fun(w, &ret, include_corners); \ + return ret; \ + } + /// Generate a "return by value" function, from a function that returns the /// region via a region_t pointer argument. /// Function signature has to be (win *, region_t *) @@ -186,16 +197,18 @@ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) { /** * Get a rectangular region a window occupies, excluding shadow. */ -static void win_get_region_local(const struct managed_win *w, region_t *res) { +static void win_get_region_local(const struct managed_win *w, region_t *res, bool include_corners) { assert(w->widthb >= 0 && w->heightb >= 0); pixman_region32_fini(res); pixman_region32_init_rect(res, 0, 0, (uint)w->widthb, (uint)w->heightb); + + if(!include_corners) win_region_remove_corners(w, res); } /** * Get a rectangular region a window occupies, excluding frame and shadow. */ -void win_get_region_noframe_local(const struct managed_win *w, region_t *res) { +void win_get_region_noframe_local(const struct managed_win *w, region_t *res, bool include_corners) { const margin_t extents = win_calc_frame_extents(w); int x = extents.left; @@ -206,10 +219,11 @@ void win_get_region_noframe_local(const struct managed_win *w, region_t *res) { pixman_region32_fini(res); if (width > 0 && height > 0) { pixman_region32_init_rect(res, x, y, (uint)width, (uint)height); + if(!include_corners) win_region_remove_corners(w, res); } } -void win_get_region_frame_local(const struct managed_win *w, region_t *res) { +void win_get_region_frame_local(const struct managed_win *w, region_t *res, bool include_corners) { const margin_t extents = win_calc_frame_extents(w); pixman_region32_fini(res); pixman_region32_init_rects( @@ -230,10 +244,11 @@ void win_get_region_frame_local(const struct managed_win *w, region_t *res) { region_t reg_win; pixman_region32_init_rect(®_win, 0, 0, w->g.width, w->g.height); pixman_region32_intersect(res, ®_win, res); + if(!include_corners) win_region_remove_corners(w, res); pixman_region32_fini(®_win); } -gen_by_val(win_get_region_frame_local); +gen_by_val_corners(win_get_region_frame_local); /** * Add a window to damaged area. @@ -1240,6 +1255,8 @@ struct win *fill_win(session_t *ps, struct win *w) { // Initialized during paint .paint = PAINT_INIT, .shadow_paint = PAINT_INIT, + + .corner_radius = 0, }; assert(!w->destroyed); @@ -1540,7 +1557,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { pixman_region32_clear(&w->bounding_shape); // Start with the window rectangular region - win_get_region_local(w, &w->bounding_shape); + win_get_region_local(w, &w->bounding_shape, true); // Only request for a bounding region if the window is shaped // (while loop is used to avoid goto, not an actual loop) diff --git a/src/win.h b/src/win.h index 3b374e57bd..03048f667d 100644 --- a/src/win.h +++ b/src/win.h @@ -200,6 +200,9 @@ struct managed_win { /// Last window opacity value set by the rules. double opacity_set; + /// Corner radius + int corner_radius; + // Fading-related members /// Override value of window fade state. Set by D-Bus method calls. switch_t fade_force; @@ -355,12 +358,12 @@ void add_damage_from_win(session_t *ps, const struct managed_win *w); * * Return region in global coordinates. */ -void win_get_region_noframe_local(const struct managed_win *w, region_t *); +void win_get_region_noframe_local(const struct managed_win *w, region_t *, bool include_corners); /// Get the region for the frame of the window -void win_get_region_frame_local(const struct managed_win *w, region_t *res); +void win_get_region_frame_local(const struct managed_win *w, region_t *res, bool include_corners); /// Get the region for the frame of the window, by value -region_t win_get_region_frame_local_by_val(const struct managed_win *w); +region_t win_get_region_frame_local_by_val(const struct managed_win *w, bool include_corners); /** * Retrieve frame extents from a window. */ @@ -436,10 +439,25 @@ struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps, /// Free all resources in a struct win void free_win_res(session_t *ps, struct managed_win *w); -static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w) { +static inline void win_region_remove_corners(const struct managed_win *w, region_t *res) { + region_t corners; + pixman_region32_init_rects( + &corners, + (rect_t[]){ + {.x1 = 0, .y1 = 0, .x2 = w->corner_radius, .y2 = w->corner_radius}, + {.x1 = 0, .y1 = w->heightb-w->corner_radius, .x2 = w->corner_radius, .y2 = w->heightb}, + {.x1 = w->widthb-w->corner_radius, .y1 = 0, .x2 = w->widthb, .y2 = w->corner_radius}, + {.x1 = w->widthb-w->corner_radius, .y1 = w->heightb-w->corner_radius, .x2 = w->widthb, .y2 = w->heightb}, + }, + 4); + pixman_region32_subtract(res, res, &corners); +} + +static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w, bool include_corners) { region_t ret; pixman_region32_init(&ret); pixman_region32_copy(&ret, &w->bounding_shape); + if(!include_corners) win_region_remove_corners(w, &ret); pixman_region32_translate(&ret, w->g.x, w->g.y); return ret; } diff --git a/src/x.c b/src/x.c index fe162d269e..34b857ff51 100644 --- a/src/x.c +++ b/src/x.c @@ -167,6 +167,15 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_ return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id); } +xcb_render_pictformat_t +x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { + x_get_server_pictfmts(c); + + auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std); + + return pictfmt->id; +} + int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) { auto setup = xcb_get_setup(c); for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; @@ -231,6 +240,17 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr); } +xcb_render_picture_t +x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, + xcb_pict_standard_t standard, uint32_t valuemask, + const xcb_render_create_picture_value_list_t *attr) { + x_get_server_pictfmts(c); + + auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard); + assert(pictfmt); + return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr); +} + /** * Create an picture. */ diff --git a/src/x.h b/src/x.h index e98b21154d..3fc4848295 100644 --- a/src/x.h +++ b/src/x.h @@ -167,6 +167,12 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_ const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1); +xcb_render_picture_t +x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, + xcb_pict_standard_t standard, uint32_t valuemask, + const xcb_render_create_picture_value_list_t *attr) + attr_nonnull(1); + /** * Create an picture. */ @@ -250,6 +256,9 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); +xcb_render_pictformat_t +x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); + xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen); uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c); From 370afc319b48ed4d99ec618b6b1cd1195eaab085 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 30 Aug 2019 12:31:52 +0100 Subject: [PATCH 02/38] Don't round fullscreen windows --- src/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index 476a72a56a..bf7dfb9313 100644 --- a/src/render.c +++ b/src/render.c @@ -316,7 +316,7 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool neg = (w && w->invert_color); - render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w ? w->corner_radius : 0), + render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) ? w->corner_radius : 0), pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL w ? &ps->glx_prog_win : NULL From 826ab2561f3ae45ae5e4a94a085a6444569e95b7 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 30 Aug 2019 15:24:38 +0100 Subject: [PATCH 03/38] Use a mask for rounded corners --- src/render.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/render.c b/src/render.c index bf7dfb9313..9eeb6d8f97 100644 --- a/src/render.c +++ b/src/render.c @@ -265,13 +265,13 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr, traps + n); - xcb_render_trapezoids( - ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, - x_get_pictfmt_for_standard(ps->c, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8 ), - to_i16_checked(cr), 0, n, traps); + xcb_render_trapezoids( + ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, + x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_ARGB_32), + 0, 0, n, traps); xcb_render_composite( - ps->c, XCB_RENDER_PICT_OP_OVER, p_tmp, alpha_pict, + ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx), to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); From 24fae5e39d82cd58005812b479ab26a9d6bf086b Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 30 Aug 2019 15:43:22 +0100 Subject: [PATCH 04/38] Fix bug where the wrong standard was used --- src/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index 9eeb6d8f97..09eb034e38 100644 --- a/src/render.c +++ b/src/render.c @@ -267,7 +267,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl xcb_render_trapezoids( ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, - x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_ARGB_32), + x_get_pictfmt_for_standard(ps->c, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8), 0, 0, n, traps); xcb_render_composite( From 43acc203ddf74a75380e5a3e3640fdd3bc732c2f Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 30 Aug 2019 18:01:09 +0100 Subject: [PATCH 05/38] Fix bug where the wrong standard was being used - again --- src/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index 09eb034e38..f5463edf7c 100644 --- a/src/render.c +++ b/src/render.c @@ -267,7 +267,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl xcb_render_trapezoids( ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, - x_get_pictfmt_for_standard(ps->c, argb ? XCB_PICT_STANDARD_ARGB_32 : XCB_PICT_STANDARD_A_8), + x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); xcb_render_composite( From 8b9c097fbf9e82bff2444f9ca1981615113c5290 Mon Sep 17 00:00:00 2001 From: elenapan Date: Tue, 17 Dec 2019 04:54:02 +0200 Subject: [PATCH 06/38] Add rounded-corners-exclude configuration option Allows the user to selectively disable rounded corners. --- man/picom.1.asciidoc | 3 +++ src/config.c | 2 ++ src/config.h | 3 +++ src/config_libconfig.c | 2 ++ src/options.c | 5 +++++ src/picom.c | 2 ++ src/render.c | 2 +- 7 files changed, 18 insertions(+), 1 deletion(-) diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index 0308508636..f01ef3eeab 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -109,6 +109,9 @@ OPTIONS *--corner-radius* 'VALUE':: Round the corners of windows. (defaults to 0). +*--rounded-corners-exclude* 'CONDITION':: + Exclude conditions for rounded corners. + *--mark-wmwin-focused*:: Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active. diff --git a/src/config.c b/src/config.c index 764dc556cb..b93b216e09 100644 --- a/src/config.c +++ b/src/config.c @@ -561,6 +561,8 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .track_wdata = false, .track_leader = false, + + .rounded_corners_blacklist = NULL }; char *ret = NULL; diff --git a/src/config.h b/src/config.h index faebd930b0..19a48e7a7f 100644 --- a/src/config.h +++ b/src/config.h @@ -239,7 +239,10 @@ typedef struct options { // Make transparent windows clip other windows, instead of blending on top of // them bool transparent_clipping; + // === Rounded corners related === int corner_radius; + /// Rounded corners blacklist. A linked list of conditions. + c2_lptr_t *rounded_corners_blacklist; } options_t; extern const char *const BACKEND_STRS[NUM_BKEND + 1]; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 3c70aa78b4..5b075f20c2 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -241,6 +241,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad opt->active_opacity = normalize_d(dval); // --corner-radius config_lookup_int(&cfg, "corner-radius", &opt->corner_radius); + // --rounded-corners-exclude + parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude"); // -e (frame_opacity) config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); // -c (shadow_enable) diff --git a/src/options.c b/src/options.c index 17bb7fff28..6c067e7189 100644 --- a/src/options.c +++ b/src/options.c @@ -117,6 +117,9 @@ static void usage(const char *argv0, int ret) { "--corner-radius value\n" " Round the corners of windows. (defaults to 0)\n" "\n" + "--rounded-corners-exclude condition\n" + " Exclude conditions for rounded corners.\n" + "\n" "--mark-wmwin-focused\n" " Try to detect WM windows and mark them as active.\n" "\n" @@ -441,6 +444,7 @@ static const struct option longopts[] = { {"blur-size", required_argument, NULL, 329}, {"blur-deviation", required_argument, NULL, 330}, {"corner-radius", required_argument, NULL, 331}, + {"rounded-corners-exclude", required_argument, NULL, 332}, {"experimental-backends", no_argument, NULL, 733}, {"monitor-repaint", no_argument, NULL, 800}, {"diagnostics", no_argument, NULL, 801}, @@ -847,6 +851,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, break; case 331: opt->corner_radius = atoi(optarg); break; + case 332: condlst_add(&opt->rounded_corners_blacklist, optarg); break; P_CASEBOOL(733, experimental_backends); P_CASEBOOL(800, monitor_repaint); case 801: opt->print_diagnostics = true; break; diff --git a/src/picom.c b/src/picom.c index e76611f440..e6eb0aff60 100644 --- a/src/picom.c +++ b/src/picom.c @@ -1828,6 +1828,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, c2_list_postprocess(ps, ps->o.blur_background_blacklist) && c2_list_postprocess(ps, ps->o.invert_color_list) && c2_list_postprocess(ps, ps->o.opacity_rules) && + c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) && c2_list_postprocess(ps, ps->o.focus_blacklist))) { log_error("Post-processing of conditionals failed, some of your rules " "might not work"); @@ -2167,6 +2168,7 @@ static void session_destroy(session_t *ps) { free_wincondlst(&ps->o.opacity_rules); free_wincondlst(&ps->o.paint_blacklist); free_wincondlst(&ps->o.unredir_if_possible_blacklist); + free_wincondlst(&ps->o.rounded_corners_blacklist); // Free tracked atom list { diff --git a/src/render.c b/src/render.c index f5463edf7c..1e1c916149 100644 --- a/src/render.c +++ b/src/render.c @@ -316,7 +316,7 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool neg = (w && w->invert_color); - render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) ? w->corner_radius : 0), + render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0), pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL w ? &ps->glx_prog_win : NULL From e3c47bef3fc52551e72191b154524dfedb666d4f Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Thu, 23 Jan 2020 14:36:11 +0000 Subject: [PATCH 07/38] Fix rounded corners when using transparent frames, and blurred backgrounds (Hacky WIP) --- src/render.c | 69 +++++++++++++++++++++++++++++++++++----------------- src/render.h | 2 +- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/render.c b/src/render.c index 1e1c916149..8204054110 100644 --- a/src/render.c +++ b/src/render.c @@ -230,7 +230,22 @@ uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t t return 1; } -void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity, +uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei) +{ + uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps); + n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n); + n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n); + n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n); + n += make_rectangle(0, cr, cr, hei - 2 * cr, traps + n); + n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n); + n += make_rectangle(wid - cr, cr, cr, hei - 2 * cr, traps + n); + n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n); + n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr, + traps + n); + return n; +} + +void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram) { switch (ps->o.backend) { @@ -241,29 +256,20 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl if (alpha_step != 0) { if (cr) { xcb_render_picture_t p_tmp = x_create_picture_with_standard( - ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { .red = 0, .blue = 0, .green = 0, .alpha = 0}; const xcb_rectangle_t rect = {.x = 0, .y = 0, - .width = to_u16_checked(wid), - .height = to_u16_checked(hei)}; + .width = to_u16_checked(fullwid), + .height = to_u16_checked(fullhei)}; xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, p_tmp, trans, 1, &rect); - uint32_t max_ntraps = 15; + uint32_t max_ntraps = to_u32_checked(cr); xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; - uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps); - n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n); - n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n); - n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n); - n += make_rectangle(0, cr, cr, hei - 2 * cr, traps + n); - n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n); - n += make_rectangle(wid - cr, cr, cr, hei - 2 * cr, traps + n); - n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n); - n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr, - traps + n); + uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei); xcb_render_trapezoids( ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, @@ -273,7 +279,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl xcb_render_composite( ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), - 0, 0, to_i16_checked(dx), to_i16_checked(dy), + to_i16_checked(x), to_i16_checked(y), to_i16_checked(dx), to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); xcb_render_free_picture(ps->c, p_tmp); @@ -313,10 +319,12 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, double opacity, const region_t *reg_paint, xcb_render_picture_t pict) { const int dx = (w ? w->g.x : 0) + x; const int dy = (w ? w->g.y : 0) + y; + const int fullwid = w ? w->widthb : 0; + const int fullhei = w ? w-> heightb : 0; const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool neg = (w && w->invert_color); - render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0), + render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0), pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL w ? &ps->glx_prog_win : NULL @@ -700,7 +708,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { } render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, - w->shadow_height, w->shadow_opacity, true, false, 0, w->shadow_paint.pict, + w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL); } @@ -721,7 +729,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { */ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y, uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns, - int nkernels, const region_t *reg_clip) { + int nkernels, const region_t *reg_clip, xcb_render_picture_t rounded) { assert(blur_kerns); assert(blur_kerns[0]); @@ -766,7 +774,7 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t } if (src_pict != tgt_buffer) - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, + xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); free_picture(ps->c, &tmp_picture); @@ -784,6 +792,8 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); + //TODO: This really needs refactoring into a function + const int cr = w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0; double factor_center = 1.0; // Adjust blur strength according to window opacity, to make it appear @@ -815,9 +825,23 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t &ps->blur_kerns_cache[i]); } + xcb_render_picture_t td = XCB_NONE; + if (cr) { + uint32_t max_ntraps = to_u32_checked(cr); + xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; + uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, wid, hei); + + td = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0}; + const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)}; + xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); + + xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + } + // Minimize the region we try to blur, if the window itself is not // opaque, only the frame is. - region_t reg_blur = win_get_bounding_shape_global_by_val(w, false); + region_t reg_blur = win_get_bounding_shape_global_by_val(w, true); if (w->mode == WMODE_FRAME_TRANS && !ps->o.force_win_blend) { region_t reg_noframe; pixman_region32_init(®_noframe); @@ -826,10 +850,11 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t pixman_region32_subtract(®_blur, ®_blur, ®_noframe); pixman_region32_fini(®_noframe); } + // Translate global coordinates to local ones pixman_region32_translate(®_blur, -x, -y); xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, - ps->o.blur_kernel_count, ®_blur); + ps->o.blur_kernel_count, ®_blur, td); pixman_region32_clear(®_blur); } break; #ifdef CONFIG_OPENGL diff --git a/src/render.h b/src/render.h index 545e90844a..07e1e4bd61 100644 --- a/src/render.h +++ b/src/render.h @@ -25,7 +25,7 @@ typedef struct paint { #endif } paint_t; -void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity, +void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); From 00a6c09ab40c84c2662ff9f2396972b9271c4c84 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Wed, 25 Mar 2020 20:09:43 -0700 Subject: [PATCH 08/38] rebased rounded_corners to experimental-backends --- src/backend/backend.c | 10 +++---- src/backend/backend.h | 5 +++- src/backend/backend_common.c | 1 + src/backend/dummy/dummy.c | 2 +- src/backend/gl/gl_common.c | 2 +- src/backend/gl/gl_common.h | 2 +- src/backend/xrender/xrender.c | 54 +++++++++++++++++++++++++++++++---- src/picom.c | 8 +++++- src/render.c | 19 ++++++------ 9 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index bb0af5a9ce..c49bccdd20 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -151,7 +151,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { } if (ps->root_image) { - ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0, + ps->backend_data->ops->compose(ps->backend_data, t, ps->root_image, 0, 0, ®_paint, ®_visible); } @@ -283,7 +283,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { assert(w->shadow_image); if (w->opacity == 1) { ps->backend_data->ops->compose( - ps->backend_data, w->shadow_image, w->g.x + w->shadow_dx, + ps->backend_data, w, w->shadow_image, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, ®_shadow, ®_visible); } else { auto new_img = ps->backend_data->ops->copy( @@ -292,7 +292,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img, NULL, ®_visible, (double[]){w->opacity}); ps->backend_data->ops->compose( - ps->backend_data, new_img, w->g.x + w->shadow_dx, + ps->backend_data, w, new_img, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, ®_shadow, ®_visible); ps->backend_data->ops->release_image(ps->backend_data, new_img); } @@ -308,7 +308,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // Draw window on target if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) { - ps->backend_data->ops->compose(ps->backend_data, w->win_image, + ps->backend_data->ops->compose(ps->backend_data, w, w->win_image, w->g.x, w->g.y, ®_paint_in_bound, ®_visible); } else if (w->opacity * MAX_ALPHA >= 1) { @@ -368,7 +368,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img, NULL, ®_visible_local, (double[]){w->opacity}); } - ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x, + ps->backend_data->ops->compose(ps->backend_data, w, new_img, w->g.x, w->g.y, ®_paint_in_bound, ®_visible); ps->backend_data->ops->release_image(ps->backend_data, new_img); diff --git a/src/backend/backend.h b/src/backend/backend.h index 5a18e0ac01..c1fa31c240 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -28,6 +28,9 @@ typedef struct backend_base { /// Whether the backend can accept new render request at the moment bool busy; // ... + + // Session data + session_t *ps; } backend_t; typedef void (*backend_ready_callback_t)(void *); @@ -126,7 +129,7 @@ struct backend_operations { * @param reg_paint the clip region, in target coordinates * @param reg_visible the visible region, in target coordinates */ - void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y, + void (*compose)(backend_t *backend_data, struct managed_win *const w, void *image_data, int dst_x, int dst_y, const region_t *reg_paint, const region_t *reg_visible); /// Fill rectangle of the rendering buffer, mostly for debug purposes, optional. diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index ccdcaac21d..fe19266aa0 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -342,4 +342,5 @@ void init_backend_base(struct backend_base *base, session_t *ps) { base->root = ps->root; base->busy = false; base->ops = NULL; + base->ps = ps; } diff --git a/src/backend/dummy/dummy.c b/src/backend/dummy/dummy.c index 4b24f9fd58..dac08c2b6a 100644 --- a/src/backend/dummy/dummy.c +++ b/src/backend/dummy/dummy.c @@ -56,7 +56,7 @@ static void dummy_check_image(struct backend_base *base, const struct dummy_imag assert(*tmp->refcount > 0); } -void dummy_compose(struct backend_base *base, void *image, int dst_x attr_unused, +void dummy_compose(struct backend_base *base, struct managed_win *w attr_unused, void *image, int dst_x attr_unused, int dst_y attr_unused, const region_t *reg_paint attr_unused, const region_t *reg_visible attr_unused) { dummy_check_image(base, image); diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index ec19d03fbc..ffdfc60cb6 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -503,7 +503,7 @@ x_rect_to_coords(int nrects, const rect_t *rects, int dst_x, int dst_y, int text } // TODO: make use of reg_visible -void gl_compose(backend_t *base, void *image_data, int dst_x, int dst_y, +void gl_compose(backend_t *base, struct managed_win *w attr_unused, void *image_data, int dst_x, int dst_y, const region_t *reg_tgt, const region_t *reg_visible attr_unused) { struct gl_data *gd = (void *)base; struct gl_image *img = image_data; diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 0a4ff49345..3696a6ab0c 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -98,7 +98,7 @@ GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_ /** * @brief Render a region with texture data. */ -void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt, +void gl_compose(backend_t *, struct managed_win *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt, const region_t *reg_visible); void gl_resize(struct gl_data *, int width, int height); diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index a44dbc197d..34181065d4 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -90,7 +90,9 @@ struct _xrender_image_data { bool owned; }; -static void compose(backend_t *base, void *img_data, int dst_x, int dst_y, +uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei); + +static void compose(backend_t *base, struct managed_win *w, void *img_data, int dst_x, int dst_y, const region_t *reg_paint, const region_t *reg_visible) { struct _xrender_data *xd = (void *)base; struct _xrender_image_data *img = img_data; @@ -104,10 +106,52 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y, // sure we get everything into the buffer x_clear_picture_clip_region(base->c, img->pict); - x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®); - xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0, - to_i16_checked(dst_x), to_i16_checked(dst_y), - to_u16_checked(img->ewidth), to_u16_checked(img->eheight)); + // Are we rounding corners? + session_t *ps = base->ps; + int cr = (w ? w->corner_radius : 0); + + if (cr == 0) { + x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®); + xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0, + to_i16_checked(dst_x), to_i16_checked(dst_y), + to_u16_checked(img->ewidth), to_u16_checked(img->eheight)); + } else { + // Rounded corners + const int fullwid = w ? w->widthb : 0; + const int fullhei = w ? w-> heightb : 0; + //const int fullwid = img->width; + //const int fullhei = img->height; + //log_warn("f(%d, %d) imge(%d %d) imgf(%d %d) sdw(%d %d) dst(%d %d)", fullwid, fullhei, img->ewidth, img->eheight, img->width, img->height, w->shadow_width, w->shadow_height, dst_x, dst_y); + xcb_render_picture_t p_tmp = x_create_picture_with_standard( + ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + xcb_render_color_t trans = { + .red = 0, .blue = 0, .green = 0, .alpha = 0}; + const xcb_rectangle_t rect = {.x = 0, + .y = 0, + .width = to_u16_checked(fullwid), + .height = to_u16_checked(fullhei)}; + xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, + p_tmp, trans, 1, &rect); + + uint32_t max_ntraps = to_u32_checked(cr); + xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; + + uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei); + + xcb_render_trapezoids( + ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, + x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), + 0, 0, n, traps); + + x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®); + xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OVER, img->pict, p_tmp, xd->back[2], + 1, 1, 0, 0, + //0, 0, to_i16_checked(x), to_i16_checked(y), + to_i16_checked(dst_x), to_i16_checked(dst_y), + to_u16_checked(img->ewidth), to_u16_checked(img->eheight)); + + xcb_render_free_picture(ps->c, p_tmp); + } pixman_region32_fini(®); } diff --git a/src/picom.c b/src/picom.c index e6eb0aff60..bbc911b8e1 100644 --- a/src/picom.c +++ b/src/picom.c @@ -472,7 +472,13 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { w->frame_opacity = 1.0; } - w->corner_radius = ps->o.corner_radius; + // Don't round full screen windows & excluded windows + if ((w && win_is_fullscreen(ps, w)) || + c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) { + w->corner_radius = 0; + } else { + w->corner_radius = ps->o.corner_radius; + } // Update window mode w->mode = win_calc_mode(w); diff --git a/src/render.c b/src/render.c index 8204054110..ecac112a88 100644 --- a/src/render.c +++ b/src/render.c @@ -255,6 +255,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step]; if (alpha_step != 0) { if (cr) { + //log_warn("f(%d, %d) wh(%d %d) xy(%d %d) dxy(%d %d)", fullwid, fullhei, wid, hei, x, y, dx, dy); xcb_render_picture_t p_tmp = x_create_picture_with_standard( ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { @@ -269,12 +270,12 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f uint32_t max_ntraps = to_u32_checked(cr); xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; - uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei); + uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei); - xcb_render_trapezoids( - ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, - x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), - 0, 0, n, traps); + xcb_render_trapezoids( + ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, + x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), + 0, 0, n, traps); xcb_render_composite( ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, @@ -324,8 +325,9 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool neg = (w && w->invert_color); - render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, (w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0), - pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, + render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, + (w ? w->corner_radius : 0), + pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL w ? &ps->glx_prog_win : NULL #else @@ -792,8 +794,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); - //TODO: This really needs refactoring into a function - const int cr = w && !win_is_fullscreen(ps, w) && !c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL) ? w->corner_radius : 0; + const int cr = (w ? w->corner_radius : 0); double factor_center = 1.0; // Adjust blur strength according to window opacity, to make it appear From c540c448361e24dd5d0fdbc89d40020776de33ae Mon Sep 17 00:00:00 2001 From: bhagwan Date: Wed, 25 Mar 2020 20:22:57 -0700 Subject: [PATCH 09/38] fixed leftover bug from testing --- src/backend/xrender/xrender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 34181065d4..d4444cefdc 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -145,7 +145,7 @@ static void compose(backend_t *base, struct managed_win *w, void *img_data, int x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®); xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OVER, img->pict, p_tmp, xd->back[2], - 1, 1, 0, 0, + 0, 0, 0, 0, //0, 0, to_i16_checked(x), to_i16_checked(y), to_i16_checked(dst_x), to_i16_checked(dst_y), to_u16_checked(img->ewidth), to_u16_checked(img->eheight)); From 4ce5d641f27f0a59f755d8cd2e8c5a26e4d6bbc4 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Fri, 27 Mar 2020 09:23:05 -0700 Subject: [PATCH 10/38] WIP: added fragment shader skeleton for rounded corners on glx --- src/backend/xrender/xrender.c | 2 +- src/opengl.c | 272 ++++++++++++++++++++++++++++++++++ src/opengl.h | 17 +++ src/render.c | 46 ++++++ src/win.h | 1 + 5 files changed, 337 insertions(+), 1 deletion(-) diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index d4444cefdc..ee35e216a7 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -121,7 +121,7 @@ static void compose(backend_t *base, struct managed_win *w, void *img_data, int const int fullhei = w ? w-> heightb : 0; //const int fullwid = img->width; //const int fullhei = img->height; - //log_warn("f(%d, %d) imge(%d %d) imgf(%d %d) sdw(%d %d) dst(%d %d)", fullwid, fullhei, img->ewidth, img->eheight, img->width, img->height, w->shadow_width, w->shadow_height, dst_x, dst_y); + //log_warn("f(%d, %d) imge(%d %d) imgf(%d %d) sdw(%d %d) dst(%d %d) s:%d b:%d", fullwid, fullhei, img->ewidth, img->eheight, img->width, img->height, w->shadow_width, w->shadow_height, dst_x, dst_y, w->shadow, w->g.border_width); xcb_render_picture_t p_tmp = x_create_picture_with_standard( ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { diff --git a/src/opengl.c b/src/opengl.c index e5a57ca8e1..cce6ee4b24 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -98,6 +98,13 @@ bool glx_init(session_t *ps, bool need_render) { ppass->unifm_offset_x = -1; ppass->unifm_offset_y = -1; } + + ps->psglx->round_passes = ccalloc(1, glx_round_pass_t); + { + glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + ppass->unifm_offset_x = -1; + ppass->unifm_offset_y = -1; + } } glx_session_t *psglx = ps->psglx; @@ -242,6 +249,15 @@ void glx_destroy(session_t *ps) { } free(ps->psglx->blur_passes); + { + glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + if (ppass->frag_shader) + glDeleteShader(ppass->frag_shader); + if (ppass->prog) + glDeleteProgram(ppass->prog); + free(ps->psglx->round_passes); + } + glx_free_prog_main(&ps->glx_prog_win); gl_check_err(); @@ -416,6 +432,125 @@ bool glx_init_blur(session_t *ps) { return true; } +/** + * Initialize GLX rounded corners filter. + */ +bool glx_init_rounded_corners(session_t *ps) { + + log_warn("glx_init_rounded_corners: cr=%d", ps->o.corner_radius); + + { + char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); + // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane + // Thanks to hiciu for reporting. + setlocale(LC_NUMERIC, "C"); + + static const char *FRAG_SHADER_PREFIX = + "#version 110\n" + "%s" // extensions + "uniform float offset_x;\n" + "uniform float offset_y;\n" + "uniform %s tex_scr;\n" // sampler2D | sampler2DRect + "uniform vec2 tex_size;\n" + "//layout(location = 0) out vec4 out_color;\n" + "\n" + "void main()\n" + "{\n" + "\n"; + + // Fragment shader (round corners) + static const char *FRAG_SHADER_ROUND_CORNERS = + " vec4 sum = vec4(offset_x, offset_y, 0.0, 0.0);\n" + " //gl_FragColor = sum / 8.0;\n" + "\n" + " //vec4 in_color = texture(tex_scr, gl_FragCoord.xy / tex_size);" + " //gl_FragColor = in_color;\n" + " //gl_FragColor.a = 0.5;\n" + " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + "}\n"; + + const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; + const char *sampler_type = (use_texture_rect ? "sampler2DRect": "sampler2D"); + const char *texture_func = (use_texture_rect ? "texture2DRect": "texture2D"); + char *extension = NULL; + if (use_texture_rect) { + mstrextend(&extension, "#extension GL_ARB_texture_rectangle : " + "require\n"); + } + if (!extension) { + extension = strdup(""); + } + + // Build rounded corners shader + glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + { + auto len = strlen(FRAG_SHADER_PREFIX) + strlen(extension) + + strlen(sampler_type) + strlen(texture_func) + + strlen(FRAG_SHADER_ROUND_CORNERS) + 1; + char *shader_str = calloc(len, sizeof(char)); + if (!shader_str) { + log_error("Failed to allocate %zd bytes for shader string.", len); + return false; + } + + char *pc = shader_str; + sprintf(pc, FRAG_SHADER_PREFIX, extension, sampler_type, texture_func); + pc += strlen(pc); + assert(strlen(shader_str) < len); + + sprintf(pc, FRAG_SHADER_ROUND_CORNERS); + assert(strlen(shader_str) < len); +#ifdef DEBUG_GLX + log_debug("Generated rounded corners shader:\n%s\n", shader_str); +#endif + + log_warn("Generated rounded corners shader:\n%s\n", shader_str); + ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); + free(shader_str); + + if (!ppass->frag_shader) { + log_error("Failed to create rounded corners fragment shader."); + free(extension); + free(lc_numeric_old); + return false; + } + + // Build program + ppass->prog = gl_create_program(&ppass->frag_shader, 1); + if (!ppass->prog) { + log_error("Failed to create GLSL program."); + free(extension); + free(lc_numeric_old); + return false; + } + + // Get uniform addresses +#define P_GET_UNIFM_LOC(name, target) \ + { \ + ppass->target = glGetUniformLocation(ppass->prog, name); \ + if (ppass->target < 0) { \ + log_error("Failed to get location of rounded corners uniform '" name \ + "'. Might be troublesome." \ + ); \ + } \ + } + 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); + + // Restore LC_NUMERIC + setlocale(LC_NUMERIC, lc_numeric_old); + free(lc_numeric_old); + } + + gl_check_err(); + + return true; +} + /** * Load a GLSL main program from shader strings. */ @@ -889,6 +1024,143 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, return ret; } +bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, int height, float z attr_unused, + GLfloat factor_center attr_unused, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { + + assert(ps->psglx->round_passes[0].prog); + const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); + const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); + bool ret = false; + + log_warn("dxy(%d, %d) wh(%d %d)", dx, dy, width, height); + + // 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; + // log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight); + + GLenum tex_tgt = GL_TEXTURE_RECTANGLE; + if (ps->psglx->has_texture_non_power_of_two) + tex_tgt = GL_TEXTURE_2D; + + // Free textures if size inconsistency discovered + if (mwidth != pbc->width || mheight != pbc->height) + free_glx_bc_resize(ps, pbc); + + // Generate FBO and textures if needed + if (!pbc->textures[0]) + pbc->textures[0] = glx_gen_texture(tex_tgt, mwidth, mheight); + GLuint tex_scr = pbc->textures[0]; + + pbc->width = mwidth; + pbc->height = mheight; + + if (!pbc->fbo) + glGenFramebuffers(1, &pbc->fbo); + const GLuint fbo = pbc->fbo; + + if (!tex_scr) { + log_error("Failed to allocate texture."); + goto glx_round_corners_dst_end; + } + if (!fbo) { + log_error("Failed to allocate framebuffer."); + goto glx_round_corners_dst_end; + } + + // Enable alpha blend + glEnable(GL_BLEND); + //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // 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); + + // Paint it back + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + + { + const glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + assert(ppass->prog); + + assert(tex_scr); + glBindTexture(tex_tgt, tex_scr); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDrawBuffer(GL_BACK); + if (have_scissors) + glEnable(GL_SCISSOR_TEST); + if (have_stencil) + glEnable(GL_STENCIL_TEST); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glUseProgram(ppass->prog); + if (ppass->unifm_offset_x >= 0) + glUniform1f(ppass->unifm_offset_x, 0); + if (ppass->unifm_offset_y >= 0) + glUniform1f(ppass->unifm_offset_y, 0); + + P_PAINTREG_START(crect) { + auto rx = (GLfloat)(crect.x1 - mdx); + auto ry = (GLfloat)(mheight - (crect.y1 - mdy)); + auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); + auto rye = ry - (GLfloat)(crect.y2 - crect.y1); + auto rdx = (GLfloat)(crect.x1 - mdx); + auto rdy = (GLfloat)(mheight - crect.y1 + mdy); + auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); + auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); + +#ifdef DEBUG_GLX + log_debug("Rounded corner Pass: %f, %f, %f, %f -> %f, %f, %f, %f", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); +#endif + + log_warn("Rounded corner Pass: %f, %f, %f, %f -> %f, %f, %f, %f", + rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); + + glTexCoord2f(rx, ry); + glVertex3f(rdx, rdy, z); + + glTexCoord2f(rxe, ry); + glVertex3f(rdxe, rdy, z); + + glTexCoord2f(rxe, rye); + glVertex3f(rdxe, rdye, z); + + glTexCoord2f(rx, rye); + glVertex3f(rdx, rdye, z); + } + P_PAINTREG_END(); + + glUseProgram(0); + } + + ret = true; + +glx_round_corners_dst_end: + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(tex_tgt, 0); + glDisable(tex_tgt); + glDisable(GL_BLEND); + if (have_scissors) + glEnable(GL_SCISSOR_TEST); + if (have_stencil) + glEnable(GL_STENCIL_TEST); + + if (&ibc == pbc) { + free_glx_bc(ps, pbc); + } + + gl_check_err(); + + return ret; +} + bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, GLfloat factor, const region_t *reg_tgt) { // It's possible to dim in glx_render(), but it would be over-complicated diff --git a/src/opengl.h b/src/opengl.h index 033cf16ea8..cabeebdf33 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -40,6 +40,17 @@ typedef struct { GLint unifm_factor_center; } glx_blur_pass_t; +typedef struct { + /// Fragment shader for rounded corners. + GLuint frag_shader; + /// GLSL program for rounded corners. + 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; +} glx_round_pass_t; + /// Structure containing GLX-dependent data for a session. typedef struct glx_session { // === OpenGL related === @@ -50,6 +61,7 @@ typedef struct glx_session { /// Current GLX Z value. int z; glx_blur_pass_t *blur_passes; + glx_round_pass_t *round_passes; } glx_session_t; /// @brief Wrapper of a binded GLX texture. @@ -81,6 +93,8 @@ void glx_on_root_change(session_t *ps); bool glx_init_blur(session_t *ps); +bool glx_init_rounded_corners(session_t *ps); + #ifdef CONFIG_OPENGL bool glx_load_prog_main(const char *vshader_str, const char *fshader_str, glx_prog_main_t *pprogram); @@ -105,6 +119,9 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); +bool glx_round_corners_dst(session_t *ps, int dx, int dy, int width, int height, float z, + GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); + GLuint glx_create_shader(GLenum shader_type, const char *shader_str); GLuint glx_create_program(const GLuint *const shaders, int nshaders); diff --git a/src/render.c b/src/render.c index ecac112a88..b976c877e8 100644 --- a/src/render.c +++ b/src/render.c @@ -872,6 +872,39 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t #endif } +/** + * Rounde the corners of a window. + * Applies a fragment shader to discard corners + * + */ +static inline void +win_round_corners(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer attr_unused, + const region_t *reg_paint) { + const int16_t x = w->g.x; + const int16_t y = w->g.y; + const auto wid = to_u16_checked(w->widthb); + const auto hei = to_u16_checked(w->heightb); + + double factor_center = 1.0; + + switch (ps->o.backend) { + case BKEND_XRENDER: + case BKEND_XR_GLX_HYBRID: { + // XRender method is implemented inside render() + } break; +#ifdef CONFIG_OPENGL + case BKEND_GLX: + glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, + (float)factor_center, reg_paint, &w->glx_round_cache); + break; +#endif + default: assert(0); + } +#ifndef CONFIG_OPENGL + (void)reg_paint; +#endif +} + /// paint all windows /// region = ?? /// region_real = the damage region @@ -1034,6 +1067,11 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->o.force_win_blend)) win_blur_background(ps, w, ps->tgt_buffer.pict, ®_tmp); + // Rounde the corners + if (w->corner_radius > 0) { + win_round_corners(ps, w, ps->tgt_buffer.pict, ®_tmp); + } + // Painting the window paint_one(ps, w, ®_tmp); } @@ -1289,6 +1327,14 @@ bool init_render(session_t *ps) { return false; } } + + // Initialize our rounded corners fragment shader + if (ps->o.corner_radius > 0) { + if (!glx_init_rounded_corners(ps)) { + log_error("Failed to init rounded corners shader."); + return false; + } + } return true; } diff --git a/src/win.h b/src/win.h index 03048f667d..7cdfa9ced7 100644 --- a/src/win.h +++ b/src/win.h @@ -250,6 +250,7 @@ struct managed_win { #ifdef CONFIG_OPENGL /// Textures and FBO background blur use. glx_blur_cache_t glx_blur_cache; + glx_blur_cache_t glx_round_cache; #endif }; From 1b784113d6ca4c4a904a0e489c614522d7ba9d7b Mon Sep 17 00:00:00 2001 From: bhagwan Date: Fri, 27 Mar 2020 14:41:53 -0700 Subject: [PATCH 11/38] WIP: skeleton shader for rounded corners working (green mask) --- src/opengl.c | 55 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index cce6ee4b24..c9136477e5 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -1030,6 +1030,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, assert(ps->psglx->round_passes[0].prog); const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); + const bool have_blend = glIsEnabled(GL_BLEND); bool ret = false; log_warn("dxy(%d, %d) wh(%d %d)", dx, dy, width, height); @@ -1054,36 +1055,41 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (!pbc->textures[0]) pbc->textures[0] = glx_gen_texture(tex_tgt, mwidth, mheight); GLuint tex_scr = pbc->textures[0]; + //if (!pbc->textures[1]) + // pbc->textures[1] = glx_gen_texture(tex_tgt, mwidth, mheight); + //GLuint tex_scr2 = pbc->textures[1]; pbc->width = mwidth; pbc->height = mheight; - if (!pbc->fbo) - glGenFramebuffers(1, &pbc->fbo); - const GLuint fbo = pbc->fbo; + //if (!pbc->fbo) + // glGenFramebuffers(1, &pbc->fbo); + //const GLuint fbo = pbc->fbo; if (!tex_scr) { log_error("Failed to allocate texture."); goto glx_round_corners_dst_end; } - if (!fbo) { - log_error("Failed to allocate framebuffer."); - goto glx_round_corners_dst_end; - } - - // Enable alpha blend - glEnable(GL_BLEND); - //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //if (!fbo) { + // log_error("Failed to allocate framebuffer."); + // goto glx_round_corners_dst_end; + //} // 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); + // Texture scaling factor + GLfloat texfac_x = 1.0f, texfac_y = 1.0f; + if (tex_tgt == GL_TEXTURE_2D) { + texfac_x /= (GLfloat)mwidth; + texfac_y /= (GLfloat)mheight; + } + // Paint it back - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); + //glDisable(GL_STENCIL_TEST); + //glDisable(GL_SCISSOR_TEST); { const glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; @@ -1099,6 +1105,13 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (have_stencil) glEnable(GL_STENCIL_TEST); + // Enable alpha blend + if (have_blend) { + //glEnable(GL_BLEND); + //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); if (ppass->unifm_offset_x >= 0) @@ -1107,12 +1120,16 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, glUniform1f(ppass->unifm_offset_y, 0); P_PAINTREG_START(crect) { - auto rx = (GLfloat)(crect.x1 - mdx); - auto ry = (GLfloat)(mheight - (crect.y1 - mdy)); - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); - auto rye = ry - (GLfloat)(crect.y2 - crect.y1); + auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; + auto ry = (GLfloat)(mheight - (crect.y1 - mdy)) * texfac_y; + auto rxe = rx + (GLfloat)(crect.x2 - crect.x1) * texfac_x; + auto rye = ry - (GLfloat)(crect.y2 - crect.y1) * texfac_y; auto rdx = (GLfloat)(crect.x1 - mdx); auto rdy = (GLfloat)(mheight - crect.y1 + mdy); + { + rdx = (GLfloat)crect.x1; + rdy = (GLfloat)(ps->root_height - crect.y1); + } auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); @@ -1146,7 +1163,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(tex_tgt, 0); glDisable(tex_tgt); - glDisable(GL_BLEND); + //glDisable(GL_BLEND); if (have_scissors) glEnable(GL_SCISSOR_TEST); if (have_stencil) From fcb5c43bb39c11c1978a47a0d0b30fc0f4512e43 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Fri, 27 Mar 2020 21:55:43 -0700 Subject: [PATCH 12/38] wip: rounded corners shader test code semi-worikng? --- src/opengl.c | 50 +++++++++++++++++++++++++++++--------------------- src/opengl.h | 8 ++++---- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index c9136477e5..f9d9538dd2 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -101,9 +101,9 @@ bool glx_init(session_t *ps, bool need_render) { ps->psglx->round_passes = ccalloc(1, glx_round_pass_t); { - glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; - ppass->unifm_offset_x = -1; - ppass->unifm_offset_y = -1; + //glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + //ppass->unifm_radius = -1; + //ppass->unifm_resolution = -1; } } @@ -448,25 +448,33 @@ bool glx_init_rounded_corners(session_t *ps) { static const char *FRAG_SHADER_PREFIX = "#version 110\n" "%s" // extensions - "uniform float offset_x;\n" - "uniform float offset_y;\n" + "uniform float u_radius;\n" + "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect - "uniform vec2 tex_size;\n" - "//layout(location = 0) out vec4 out_color;\n" "\n" + "// from http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n" + "float udRoundBox( vec2 p, vec2 b, float r )\n" + "{\n" + " return length(max(abs(p)-b+r,0.0))-r;\n" + "}\n\n" "void main()\n" "{\n" "\n"; // Fragment shader (round corners) static const char *FRAG_SHADER_ROUND_CORNERS = - " vec4 sum = vec4(offset_x, offset_y, 0.0, 0.0);\n" - " //gl_FragColor = sum / 8.0;\n" + " vec2 halfRes = 0.5 * u_resolution.xy;\n" + "\n" + " // compute box\n" + " float b = udRoundBox( gl_FragCoord.xy - halfRes, halfRes, u_radius );\n" + "\n" + " // colorize (red / black )\n" + " vec3 c = mix( vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" + "\n" + " gl_FragColor = vec4( c, 1.0 );\n" "\n" - " //vec4 in_color = texture(tex_scr, gl_FragCoord.xy / tex_size);" - " //gl_FragColor = in_color;\n" " //gl_FragColor.a = 0.5;\n" - " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -534,8 +542,8 @@ bool glx_init_rounded_corners(session_t *ps) { ); \ } \ } - P_GET_UNIFM_LOC("offset_x", unifm_offset_x); - P_GET_UNIFM_LOC("offset_y", unifm_offset_y); + P_GET_UNIFM_LOC("u_radius", unifm_radius); + P_GET_UNIFM_LOC("u_resolution", unifm_resolution); #undef P_GET_UNIFM_LOC } @@ -1107,17 +1115,17 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, // Enable alpha blend if (have_blend) { - //glEnable(GL_BLEND); + glEnable(GL_BLEND); //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); - if (ppass->unifm_offset_x >= 0) - glUniform1f(ppass->unifm_offset_x, 0); - if (ppass->unifm_offset_y >= 0) - glUniform1f(ppass->unifm_offset_y, 0); + if (ppass->unifm_radius >= 0) + glUniform1f(ppass->unifm_radius, (float)15.0f); + if (ppass->unifm_resolution >= 0) + glUniform2f(ppass->unifm_resolution, (float)mwidth, (float)mheight); P_PAINTREG_START(crect) { auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; @@ -1163,7 +1171,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(tex_tgt, 0); glDisable(tex_tgt); - //glDisable(GL_BLEND); + glDisable(GL_BLEND); if (have_scissors) glEnable(GL_SCISSOR_TEST); if (have_stencil) diff --git a/src/opengl.h b/src/opengl.h index cabeebdf33..c8cf867af3 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -45,10 +45,10 @@ typedef struct { GLuint frag_shader; /// GLSL program for rounded corners. 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 "u_radius" in rounded-corners GLSL program. + GLint unifm_radius; + /// Location of uniform "u_resolution" in rounded-corners GLSL program. + GLint unifm_resolution; } glx_round_pass_t; /// Structure containing GLX-dependent data for a session. From dced0d797277786e49c282e2df46bcf681b38e8b Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sat, 28 Mar 2020 12:40:32 -0700 Subject: [PATCH 13/38] wip: rounded corners frag shader works with green corners --- src/opengl.c | 60 ++++++++++++++++++++++++++++++++++++++-------------- src/opengl.h | 16 +++++++++++--- src/render.c | 8 +++---- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index f9d9538dd2..4f62b82868 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -101,9 +101,14 @@ bool glx_init(session_t *ps, bool need_render) { ps->psglx->round_passes = ccalloc(1, glx_round_pass_t); { - //glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; - //ppass->unifm_radius = -1; - //ppass->unifm_resolution = -1; + glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + ppass->unifm_factor_center = -1; + ppass->unifm_offset_x = -1; + ppass->unifm_offset_y = -1; + ppass->unifm_radius = -1; + ppass->unifm_coord = -1; + ppass->unifm_fulltex = -1; + ppass->unifm_resolution = -1; } } @@ -448,32 +453,40 @@ bool glx_init_rounded_corners(session_t *ps) { static const char *FRAG_SHADER_PREFIX = "#version 110\n" "%s" // extensions + "uniform float offset_x;\n" + "uniform float offset_y;\n" + "uniform float factor_center;\n" "uniform float u_radius;\n" + "uniform vec2 u_coord;\n" + "uniform vec2 u_fulltex;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect "\n" - "// from http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n" + "// https://www.shadertoy.com/view/ldfSDj\n" "float udRoundBox( vec2 p, vec2 b, float r )\n" "{\n" " return length(max(abs(p)-b+r,0.0))-r;\n" "}\n\n" "void main()\n" "{\n" + " vec4 col = %s(tex_scr, vec2(gl_TexCoord[0].x + offset_x," + " gl_TexCoord[0].y + offset_y)) * factor_center;\n" "\n"; // Fragment shader (round corners) static const char *FRAG_SHADER_ROUND_CORNERS = - " vec2 halfRes = 0.5 * u_resolution.xy;\n" + " vec2 halfRes = 0.5 * u_fulltex.xy;\n" + " vec2 coord = vec2(u_coord.x, u_resolution.y-u_fulltex.y-u_coord.y);\n" "\n" " // compute box\n" - " float b = udRoundBox( gl_FragCoord.xy - halfRes, halfRes, u_radius );\n" + " float b = udRoundBox( gl_FragCoord.xy - coord - halfRes, halfRes, u_radius );\n" "\n" " // colorize (red / black )\n" - " vec3 c = mix( vec3(1.0,0.0,0.0), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c4 = mix( col, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" " gl_FragColor = vec4( c, 1.0 );\n" - "\n" - " //gl_FragColor.a = 0.5;\n" + " //gl_FragColor = c4;\n" " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; @@ -502,7 +515,7 @@ bool glx_init_rounded_corners(session_t *ps) { } char *pc = shader_str; - sprintf(pc, FRAG_SHADER_PREFIX, extension, sampler_type, texture_func); + sprintf(pc, FRAG_SHADER_PREFIX, extension, sampler_type, texture_func, texture_func); pc += strlen(pc); assert(strlen(shader_str) < len); @@ -542,7 +555,12 @@ bool glx_init_rounded_corners(session_t *ps) { ); \ } \ } + P_GET_UNIFM_LOC("factor_center", unifm_factor_center); + P_GET_UNIFM_LOC("offset_x", unifm_offset_x); + P_GET_UNIFM_LOC("offset_y", unifm_offset_y); P_GET_UNIFM_LOC("u_radius", unifm_radius); + P_GET_UNIFM_LOC("u_coord", unifm_coord); + P_GET_UNIFM_LOC("u_fulltex", unifm_fulltex); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); #undef P_GET_UNIFM_LOC } @@ -1032,7 +1050,7 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, return ret; } -bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, int height, float z attr_unused, +bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, int height, float z attr_unused, float cr, GLfloat factor_center attr_unused, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { assert(ps->psglx->round_passes[0].prog); @@ -1041,7 +1059,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, const bool have_blend = glIsEnabled(GL_BLEND); bool ret = false; - log_warn("dxy(%d, %d) wh(%d %d)", dx, dy, width, height); + //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; @@ -1122,10 +1140,20 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, 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 (ppass->unifm_radius >= 0) - glUniform1f(ppass->unifm_radius, (float)15.0f); + glUniform1f(ppass->unifm_radius, cr); + if (ppass->unifm_coord >= 0) + glUniform2f(ppass->unifm_coord, (float)dx, (float)dy); + if (ppass->unifm_fulltex >= 0) + glUniform2f(ppass->unifm_fulltex, (float)mwidth, (float)mheight); if (ppass->unifm_resolution >= 0) - glUniform2f(ppass->unifm_resolution, (float)mwidth, (float)mheight); + glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); P_PAINTREG_START(crect) { auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; @@ -1145,8 +1173,8 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, log_debug("Rounded corner Pass: %f, %f, %f, %f -> %f, %f, %f, %f", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); #endif - log_warn("Rounded corner Pass: %f, %f, %f, %f -> %f, %f, %f, %f", - rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); + //log_warn("Rounded corner Pass: %f, %f, %f, %f, %f, %f -> %f, %f, %f, %f", + // texfac_x, texfac_y, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); glTexCoord2f(rx, ry); glVertex3f(rdx, rdy, z); diff --git a/src/opengl.h b/src/opengl.h index c8cf867af3..bcf3f72961 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -45,9 +45,19 @@ typedef struct { GLuint frag_shader; /// GLSL program for rounded corners. GLuint prog; - /// Location of uniform "u_radius" in rounded-corners GLSL program. + /// 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; + /// Location of uniform "radius" in rounded-corners GLSL program. GLint unifm_radius; - /// Location of uniform "u_resolution" in rounded-corners GLSL program. + /// Location of uniform "coord" in rounded-corners GLSL program. + GLint unifm_coord; + /// Location of uniform "fulltex" in rounded-corners GLSL program. + GLint unifm_fulltex; + /// Location of uniform "resolution" in rounded-corners GLSL program. GLint unifm_resolution; } glx_round_pass_t; @@ -119,7 +129,7 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst(session_t *ps, int dx, int dy, int width, int height, float z, +bool glx_round_corners_dst(session_t *ps, int dx, int dy, int width, int height, float z, float cr, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); GLuint glx_create_shader(GLenum shader_type, const char *shader_str); diff --git a/src/render.c b/src/render.c index b976c877e8..95af411932 100644 --- a/src/render.c +++ b/src/render.c @@ -878,7 +878,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t * */ static inline void -win_round_corners(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer attr_unused, +win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { const int16_t x = w->g.x; const int16_t y = w->g.y; @@ -894,7 +894,7 @@ win_round_corners(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt } break; #ifdef CONFIG_OPENGL case BKEND_GLX: - glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, + glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, (float)factor_center, reg_paint, &w->glx_round_cache); break; #endif @@ -1067,9 +1067,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->o.force_win_blend)) win_blur_background(ps, w, ps->tgt_buffer.pict, ®_tmp); - // Rounde the corners + // Round the corners if (w->corner_radius > 0) { - win_round_corners(ps, w, ps->tgt_buffer.pict, ®_tmp); + win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, ®_tmp); } // Painting the window From 7deb0a58b721ea0ae67779952a6b4a82f0f349cb Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sat, 28 Mar 2020 13:26:31 -0700 Subject: [PATCH 14/38] merged with yshui/picom commit 3ba7a2a [2020-03-28] --- src/picom.c | 30 +++++++++++--------- src/x.c | 79 ++++++++++++++++++++++++++++++++--------------------- src/x.h | 47 +++++++++++++++++++------------ 3 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/picom.c b/src/picom.c index bbc911b8e1..19cab08435 100644 --- a/src/picom.c +++ b/src/picom.c @@ -860,6 +860,9 @@ void configure_root(session_t *ps, int width, int height) { ev_break(ps->loop, EVBREAK_ALL); return; } + + // Re-acquire the root pixmap. + root_damaged(ps); } force_repaint(ps); } @@ -1212,7 +1215,13 @@ static bool redirect_start(session_t *ps) { xcb_map_window(ps->c, ps->overlay); } - xcb_composite_redirect_subwindows(ps->c, ps->root, session_redirection_mode(ps)); + bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c, ps->root, + session_redirection_mode(ps)); + if (!success) { + log_fatal("Another composite manager is already running " + "(and does not handle _NET_WM_CM_Sn correctly)"); + return false; + } x_sync(ps->c); @@ -1356,9 +1365,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) { log_debug("Delayed handling of events, entering critical section"); auto e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); if (e) { - log_fatal("failed to grab x server"); - x_print_error(e->full_sequence, e->major_code, e->minor_code, - e->error_code); + log_fatal_x_error(e, "failed to grab x server"); return quit(ps); } @@ -1390,9 +1397,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) { e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c)); if (e) { - log_fatal("failed to ungrab x server"); - x_print_error(e->full_sequence, e->major_code, e->minor_code, - e->error_code); + log_fatal_x_error(e, "failed to ungrab x server"); return quit(ps); } @@ -1699,8 +1704,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE})); if (e) { - log_error("Failed to setup root window event mask"); - free(e); + log_error_x_error(e, "Failed to setup root window event mask"); } xcb_prefetch_extension_data(ps->c, &xcb_render_id); @@ -1902,8 +1906,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy, e = xcb_request_check( ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0)); if (e) { - log_error("Failed to create a XSync fence. xrender-sync-fence " - "will be disabled"); + log_error_x_error(e, "Failed to create a XSync fence. " + "xrender-sync-fence will be disabled"); ps->o.xrender_sync_fence = false; ps->sync_fence = XCB_NONE; free(e); @@ -2066,7 +2070,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); if (e) { - log_fatal("Failed to grab X server"); + log_fatal_x_error(e, "Failed to grab X server"); goto err; } @@ -2083,7 +2087,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, e = xcb_request_check(ps->c, xcb_ungrab_server(ps->c)); if (e) { - log_error("Failed to ungrab server"); + log_fatal_x_error(e, "Failed to ungrab server"); free(e); } diff --git a/src/x.c b/src/x.c index 34b857ff51..f195894fa1 100644 --- a/src/x.c +++ b/src/x.c @@ -214,8 +214,7 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c, c, tmp_picture, pixmap, pictfmt->id, valuemask, buf)); free(buf); if (e) { - x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code); - log_error("failed to create picture"); + log_error_x_error(e, "failed to create picture"); return XCB_NONE; } return tmp_picture; @@ -285,7 +284,7 @@ bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_ xcb_xfixes_fetch_region_reply_t *xr = xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e); if (!xr) { - log_error("Failed to fetch rectangles"); + log_error_x_error(e, "Failed to fetch rectangles"); return false; } @@ -321,9 +320,10 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, xcb_generic_error_t *e = xcb_request_check( c, xcb_render_set_picture_clip_rectangles_checked( c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects)); - if (e) - log_error("Failed to set clip region"); - free(e); + if (e) { + log_error_x_error(e, "Failed to set clip region"); + free(e); + } free(xrects); return; } @@ -332,9 +332,10 @@ void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE}; xcb_generic_error_t *e = xcb_request_check( c, xcb_render_change_picture(c, pict, XCB_RENDER_CP_CLIP_MASK, &v)); - if (e) - log_error("failed to clear clip region"); - free(e); + if (e) { + log_error_x_error(e, "failed to clear clip region"); + free(e); + } return; } @@ -344,25 +345,22 @@ enum { XSyncBadCounter = 0, }; /** - * X11 error handler function. + * Convert a X11 error to string * - * XXX consider making this error to string + * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used + * for multiple calls to this function, */ -void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code) { +static const char * +_x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code) { session_t *const ps = ps_g; int o = 0; const char *name = "Unknown"; - if (major == ps->composite_opcode && minor == XCB_COMPOSITE_REDIRECT_SUBWINDOWS) { - log_fatal("Another composite manager is already running " - "(and does not handle _NET_WM_CM_Sn correctly)"); - exit(1); - } - #define CASESTRRET2(s) \ case s: name = #s; break + // TODO separate error code out from session_t o = error_code - ps->xfixes_error; switch (o) { CASESTRRET2(XCB_XFIXES_BAD_REGION); } @@ -424,8 +422,27 @@ void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t #undef CASESTRRET2 - log_debug("X error %d %s request %d minor %d serial %lu", error_code, name, major, - minor, serial); + thread_local static char buffer[256]; + snprintf(buffer, sizeof(buffer), "X error %d %s request %d minor %d serial %lu", + error_code, name, major, minor, serial); + return buffer; +} + +/** + * Log a X11 error + */ +void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code) { + log_debug("%s", _x_strerror(serial, major, minor, error_code)); +} + +/* + * Convert a xcb_generic_error_t to a string that describes the error + * + * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used + * for multiple calls to this function, + */ +const char *x_strerror(xcb_generic_error_t *e) { + return _x_strerror(e->full_sequence, e->major_code, e->minor_code, e->error_code); } /** @@ -440,8 +457,7 @@ xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t if (err == NULL) return pix; - log_error("Failed to create pixmap:"); - x_print_error(err->sequence, err->major_code, err->minor_code, err->error_code); + log_error_x_error(err, "Failed to create pixmap"); free(err); return XCB_NONE; } @@ -512,25 +528,26 @@ bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) { auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f)); if (e) { - log_error("Failed to trigger the fence."); - free(e); - return false; + log_error_x_error(e, "Failed to trigger the fence"); + goto err; } e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f)); if (e) { - log_error("Failed to await on a fence."); - free(e); - return false; + log_error_x_error(e, "Failed to await on a fence"); + goto err; } e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f)); if (e) { - log_error("Failed to reset the fence."); - free(e); - return false; + log_error_x_error(e, "Failed to reset the fence"); + goto err; } return true; + +err: + free(e); + return false; } // xcb-render specific macros diff --git a/src/x.h b/src/x.h index 3fc4848295..fb57ce3062 100644 --- a/src/x.h +++ b/src/x.h @@ -50,29 +50,34 @@ struct xvisual_info { #define XCB_AWAIT_VOID(func, c, ...) \ ({ \ - bool success = true; \ - __auto_type e = xcb_request_check(c, func##_checked(c, __VA_ARGS__)); \ - if (e) { \ - x_print_error(e->sequence, e->major_code, e->minor_code, \ - e->error_code); \ - free(e); \ - success = false; \ + bool __success = true; \ + __auto_type __e = xcb_request_check(c, func##_checked(c, __VA_ARGS__)); \ + if (__e) { \ + x_print_error(__e->sequence, __e->major_code, __e->minor_code, \ + __e->error_code); \ + free(__e); \ + __success = false; \ } \ - success; \ + __success; \ }) #define XCB_AWAIT(func, c, ...) \ ({ \ - xcb_generic_error_t *e = NULL; \ - __auto_type r = func##_reply(c, func(c, __VA_ARGS__), &e); \ - if (e) { \ - x_print_error(e->sequence, e->major_code, e->minor_code, \ - e->error_code); \ - free(e); \ + xcb_generic_error_t *__e = NULL; \ + __auto_type __r = func##_reply(c, func(c, __VA_ARGS__), &__e); \ + if (__e) { \ + x_print_error(__e->sequence, __e->major_code, __e->minor_code, \ + __e->error_code); \ + free(__e); \ } \ - r; \ + __r; \ }) +#define log_error_x_error(e, fmt, ...) \ + LOG(ERROR, fmt " (%s)", ##__VA_ARGS__, x_strerror(e)) +#define log_fatal_x_error(e, fmt, ...) \ + LOG(FATAL, fmt " (%s)", ##__VA_ARGS__, x_strerror(e)) + /// Wraps x_new_id. abort the program if x_new_id returns error static inline uint32_t x_new_id(xcb_connection_t *c) { auto ret = xcb_generate_id(c); @@ -197,12 +202,18 @@ void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict); /** - * X11 error handler function. - * - * XXX consider making this error to string + * Log a X11 error */ void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code); +/* + * Convert a xcb_generic_error_t to a string that describes the error + * + * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used + * for multiple calls to this function, + */ +const char *x_strerror(xcb_generic_error_t *e); + xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable, int width, int height); From 6cc2974f574a78c0c2f5ac92d8b181e2d27e2334 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sat, 28 Mar 2020 16:11:56 -0700 Subject: [PATCH 15/38] changed some variable names in rounded corners shader --- src/opengl.c | 50 +++++++++++++++++++++----------------------------- src/opengl.h | 14 +++++--------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 4f62b82868..63ec22a2d3 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -103,11 +103,9 @@ bool glx_init(session_t *ps, bool need_render) { { glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; ppass->unifm_factor_center = -1; - ppass->unifm_offset_x = -1; - ppass->unifm_offset_y = -1; ppass->unifm_radius = -1; - ppass->unifm_coord = -1; - ppass->unifm_fulltex = -1; + ppass->unifm_texcoord = -1; + ppass->unifm_texsize = -1; ppass->unifm_resolution = -1; } } @@ -457,8 +455,8 @@ bool glx_init_rounded_corners(session_t *ps) { "uniform float offset_y;\n" "uniform float factor_center;\n" "uniform float u_radius;\n" - "uniform vec2 u_coord;\n" - "uniform vec2 u_fulltex;\n" + "uniform vec2 u_texcoord;\n" + "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect "\n" @@ -469,25 +467,25 @@ bool glx_init_rounded_corners(session_t *ps) { "}\n\n" "void main()\n" "{\n" - " vec4 col = %s(tex_scr, vec2(gl_TexCoord[0].x + offset_x," - " gl_TexCoord[0].y + offset_y)) * factor_center;\n" + " vec4 col = %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n" "\n"; // Fragment shader (round corners) static const char *FRAG_SHADER_ROUND_CORNERS = - " vec2 halfRes = 0.5 * u_fulltex.xy;\n" - " vec2 coord = vec2(u_coord.x, u_resolution.y-u_fulltex.y-u_coord.y);\n" + " vec2 halfres = 0.5 * u_texsize.xy;\n" + " vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);\n" "\n" " // compute box\n" - " float b = udRoundBox( gl_FragCoord.xy - coord - halfRes, halfRes, u_radius );\n" + " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres, u_radius );\n" "\n" " // colorize (red / black )\n" - " vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c4 = mix( col, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( col, vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" "\n" - " gl_FragColor = vec4( c, 1.0 );\n" - " //gl_FragColor = c4;\n" + " gl_FragColor = vec4( c );\n" + " //gl_FragColor = vec4( c, 1.0 );\n" " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + " //gl_FragColor = gl_Color;\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -556,11 +554,9 @@ bool glx_init_rounded_corners(session_t *ps) { } \ } P_GET_UNIFM_LOC("factor_center", unifm_factor_center); - P_GET_UNIFM_LOC("offset_x", unifm_offset_x); - P_GET_UNIFM_LOC("offset_y", unifm_offset_y); P_GET_UNIFM_LOC("u_radius", unifm_radius); - P_GET_UNIFM_LOC("u_coord", unifm_coord); - P_GET_UNIFM_LOC("u_fulltex", unifm_fulltex); + P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); + P_GET_UNIFM_LOC("u_texsize", unifm_texsize); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); #undef P_GET_UNIFM_LOC } @@ -1134,24 +1130,20 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, // Enable alpha blend if (have_blend) { glEnable(GL_BLEND); - //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } 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 (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); - if (ppass->unifm_coord >= 0) - glUniform2f(ppass->unifm_coord, (float)dx, (float)dy); - if (ppass->unifm_fulltex >= 0) - glUniform2f(ppass->unifm_fulltex, (float)mwidth, (float)mheight); + if (ppass->unifm_texcoord >= 0) + glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); + if (ppass->unifm_texsize >= 0) + glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); diff --git a/src/opengl.h b/src/opengl.h index bcf3f72961..c71eb78458 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -45,18 +45,14 @@ typedef struct { GLuint frag_shader; /// GLSL program for rounded corners. 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. + /// Location of uniform "factor_center" in rounded-corners GLSL program. GLint unifm_factor_center; /// Location of uniform "radius" in rounded-corners GLSL program. GLint unifm_radius; - /// Location of uniform "coord" in rounded-corners GLSL program. - GLint unifm_coord; - /// Location of uniform "fulltex" in rounded-corners GLSL program. - GLint unifm_fulltex; + /// Location of uniform "texcoord" in rounded-corners GLSL program. + GLint unifm_texcoord; + /// Location of uniform "texsize" in rounded-corners GLSL program. + GLint unifm_texsize; /// Location of uniform "resolution" in rounded-corners GLSL program. GLint unifm_resolution; } glx_round_pass_t; From eb40993cf7530a4ba86df40d1cdee0d43c13e105 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sun, 29 Mar 2020 08:23:04 -0700 Subject: [PATCH 16/38] moved round_corners function to the right place --- src/opengl.c | 44 +++++++++++++++++++++++------- src/render.c | 76 ++++++++++++++++++++++++++-------------------------- 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 63ec22a2d3..dbc8f66355 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -480,10 +480,12 @@ bool glx_init_rounded_corners(session_t *ps) { "\n" " // colorize (red / black )\n" " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " vec4 c = mix( col, vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( col, vec4(1.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" - " gl_FragColor = vec4( c );\n" - " //gl_FragColor = vec4( c, 1.0 );\n" + " //if ( c == vec4(0.0,1.0,0.0,0.0) ) discard; else gl_FragColor = vec4( c );\n" + " //gl_FragColor = vec4( c );\n" + " gl_FragColor = vec4( c.rgb, 0.0 );\n" " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" " //gl_FragColor = gl_Color;\n" "}\n"; @@ -1052,7 +1054,6 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, assert(ps->psglx->round_passes[0].prog); const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); - const bool have_blend = glIsEnabled(GL_BLEND); bool ret = false; //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); @@ -1127,12 +1128,13 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (have_stencil) glEnable(GL_STENCIL_TEST); - // Enable alpha blend - if (have_blend) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + // Control blending with src + glDisable(GL_BLEND); + //glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_ONE, GL_ZERO); + //glColor4f(0.0f, 0.0f, 0.0f, 0.5f); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); @@ -1182,6 +1184,28 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, } P_PAINTREG_END(); + /*P_PAINTREG_START(crect) { + // XXX what does all of these variables mean? + GLint rdx = crect.x1; + GLint rdy = ps->root_height - crect.y1; + GLint rdxe = rdx + (crect.x2 - crect.x1); + GLint rdye = rdy - (crect.y2 - crect.y1); + +#ifdef DEBUG_GLX + log_debug("Rounded corner Pass: %d, %d, %.2f -> %d, %d, %d, %d", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); +#endif + + log_warn("Rounded corner Pass: %d, %d, %.2f -> %d, %d, %d, %d", + crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); + + glVertex3i(rdx, rdy, (int)z); + glVertex3i(rdxe, rdy, (int)z); + glVertex3i(rdxe, rdye, (int)z); + glVertex3i(rdx, rdye, (int)z); + } + P_PAINTREG_END();*/ + + glColor4f(0.0f, 0.0f, 0.0f, 0.0f); glUseProgram(0); } diff --git a/src/render.c b/src/render.c index 95af411932..a551654821 100644 --- a/src/render.c +++ b/src/render.c @@ -356,6 +356,39 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { return true; } +/** + * Rounde the corners of a window. + * Applies a fragment shader to discard corners + * + */ +static inline void +win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_picture_t tgt_buffer attr_unused, + const region_t *reg_paint) { + const int16_t x = w->g.x; + const int16_t y = w->g.y; + const auto wid = to_u16_checked(w->widthb); + const auto hei = to_u16_checked(w->heightb); + + double factor_center = 1.0; + + switch (ps->o.backend) { + case BKEND_XRENDER: + case BKEND_XR_GLX_HYBRID: { + // XRender method is implemented inside render() + } break; +#ifdef CONFIG_OPENGL + case BKEND_GLX: + glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, + (float)factor_center, reg_paint, &w->glx_round_cache); + break; +#endif + default: assert(0); + } +#ifndef CONFIG_OPENGL + (void)reg_paint; +#endif +} + /** * Paint a window itself and dim it if asked. */ @@ -510,6 +543,11 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) if (pict != w->paint.pict) free_picture(ps->c, &pict); + // Round the corners + if (w->corner_radius > 0) { + win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); + } + // Dimming the window if needed if (w->dim) { double dim_opacity = ps->o.inactive_dim; @@ -872,39 +910,6 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t #endif } -/** - * Rounde the corners of a window. - * Applies a fragment shader to discard corners - * - */ -static inline void -win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_picture_t tgt_buffer attr_unused, - const region_t *reg_paint) { - const int16_t x = w->g.x; - const int16_t y = w->g.y; - const auto wid = to_u16_checked(w->widthb); - const auto hei = to_u16_checked(w->heightb); - - double factor_center = 1.0; - - switch (ps->o.backend) { - case BKEND_XRENDER: - case BKEND_XR_GLX_HYBRID: { - // XRender method is implemented inside render() - } break; -#ifdef CONFIG_OPENGL - case BKEND_GLX: - glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, - (float)factor_center, reg_paint, &w->glx_round_cache); - break; -#endif - default: assert(0); - } -#ifndef CONFIG_OPENGL - (void)reg_paint; -#endif -} - /// paint all windows /// region = ?? /// region_real = the damage region @@ -1067,11 +1072,6 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->o.force_win_blend)) win_blur_background(ps, w, ps->tgt_buffer.pict, ®_tmp); - // Round the corners - if (w->corner_radius > 0) { - win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, ®_tmp); - } - // Painting the window paint_one(ps, w, ®_tmp); } From b9cdd42a1bd6f9dca2cc8d13deab534b0ca2d678 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sun, 29 Mar 2020 20:19:51 -0700 Subject: [PATCH 17/38] round_corners function moved again --- src/opengl.c | 168 +++++++++++++++++++++++++++++++++++++-------------- src/opengl.h | 8 +-- src/picom.c | 2 +- src/render.c | 27 +++++---- src/render.h | 2 +- src/win.c | 8 ++- src/win.h | 2 +- 7 files changed, 148 insertions(+), 69 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index dbc8f66355..5364a3bfbe 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -468,6 +468,7 @@ bool glx_init_rounded_corners(session_t *ps) { "void main()\n" "{\n" " vec4 col = %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n" + " //vec4 col = vec4(1.0, 1.0, 1.0, 1.0);\n" "\n"; // Fragment shader (round corners) @@ -481,13 +482,17 @@ bool glx_init_rounded_corners(session_t *ps) { " // colorize (red / black )\n" " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" " vec4 c = mix( col, vec4(1.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" - " //if ( c == vec4(0.0,1.0,0.0,0.0) ) discard; else gl_FragColor = vec4( c );\n" - " //gl_FragColor = vec4( c );\n" - " gl_FragColor = vec4( c.rgb, 0.0 );\n" + " //if ( c == vec4(0.0,1.0,0.0,0.0) ) discard; else\n" + " gl_FragColor = vec4( c );\n" + " //gl_FragColor = vec4( c.rgb, 0.0 );\n" " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + " //gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n" + " //gl_FragColor = vec4(0.99, 0.99, 0.99, 0.99);\n" " //gl_FragColor = gl_Color;\n" + " //gl_FragColor = col;\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -1048,15 +1053,17 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, return ret; } -bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, int height, float z attr_unused, float cr, - GLfloat factor_center attr_unused, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { + +bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, + int dx, int dy, int width, int height, float z, float cr, + GLfloat factor_center, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { assert(ps->psglx->round_passes[0].prog); const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; - //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); + log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; @@ -1078,26 +1085,21 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (!pbc->textures[0]) pbc->textures[0] = glx_gen_texture(tex_tgt, mwidth, mheight); GLuint tex_scr = pbc->textures[0]; - //if (!pbc->textures[1]) - // pbc->textures[1] = glx_gen_texture(tex_tgt, mwidth, mheight); - //GLuint tex_scr2 = pbc->textures[1]; + + // Adjustments calling from glx_render() + /*if (ptex) { + tex_tgt = ptex->target; + tex_scr = ptex->texture; + }*/ pbc->width = mwidth; pbc->height = mheight; - //if (!pbc->fbo) - // glGenFramebuffers(1, &pbc->fbo); - //const GLuint fbo = pbc->fbo; - if (!tex_scr) { log_error("Failed to allocate texture."); goto glx_round_corners_dst_end; } - //if (!fbo) { - // log_error("Failed to allocate framebuffer."); - // goto glx_round_corners_dst_end; - //} - + // Read destination pixels into a texture glEnable(tex_tgt); glBindTexture(tex_tgt, tex_scr); @@ -1110,10 +1112,6 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, texfac_y /= (GLfloat)mheight; } - // Paint it back - //glDisable(GL_STENCIL_TEST); - //glDisable(GL_SCISSOR_TEST); - { const glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; assert(ppass->prog); @@ -1128,13 +1126,39 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (have_stencil) glEnable(GL_STENCIL_TEST); - // Control blending with src - glDisable(GL_BLEND); - //glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_ONE, GL_ZERO); - //glColor4f(0.0f, 0.0f, 0.0f, 0.5f); + + { + // Control blending with src + glDisable(GL_BLEND); + //glEnable(GL_BLEND); + //glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_ZERO, GL_ONE); + + // Needed for handling opacity of ARGB texture + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + // This is all weird, but X Render is using premultiplied ARGB format, and + // we need to use those things to correct it. Thanks to derhass for help. + //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + /*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);*/ + } + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); @@ -1149,7 +1173,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); - P_PAINTREG_START(crect) { + /*P_PAINTREG_START(crect) { auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; auto ry = (GLfloat)(mheight - (crect.y1 - mdy)) * texfac_y; auto rxe = rx + (GLfloat)(crect.x2 - crect.x1) * texfac_x; @@ -1182,30 +1206,80 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, glTexCoord2f(rx, rye); glVertex3f(rdx, rdye, z); } - P_PAINTREG_END(); + P_PAINTREG_END();*/ /*P_PAINTREG_START(crect) { // XXX what does all of these variables mean? - GLint rdx = crect.x1; - GLint rdy = ps->root_height - crect.y1; - GLint rdxe = rdx + (crect.x2 - crect.x1); - GLint rdye = rdy - (crect.y2 - crect.y1); + auto rdx = (GLfloat)crect.x1; + auto rdy = (GLfloat)(ps->root_height - crect.y1); + auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); + auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); #ifdef DEBUG_GLX - log_debug("Rounded corner Pass: %d, %d, %.2f -> %d, %d, %d, %d", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); + log_debug("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); #endif - log_warn("Rounded corner Pass: %d, %d, %.2f -> %d, %d, %d, %d", + log_warn("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); - glVertex3i(rdx, rdy, (int)z); - glVertex3i(rdxe, rdy, (int)z); - glVertex3i(rdxe, rdye, (int)z); - glVertex3i(rdx, rdye, (int)z); + glVertex3f(rdx, rdy, z); + glVertex3f(rdxe, rdy, z); + glVertex3f(rdxe, rdye,z); + glVertex3f(rdx, rdye, z); } P_PAINTREG_END();*/ - glColor4f(0.0f, 0.0f, 0.0f, 0.0f); + // Painting + { + P_PAINTREG_START(crect) { + // XXX explain these variables + auto rx = (GLfloat)(crect.x1 - dx); + auto ry = (GLfloat)(crect.y1 - dy); + auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); + auto rye = ry + (GLfloat)(crect.y2 - crect.y1); + // Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] + // [0-1] Thanks to amonakov for pointing out! + if (GL_TEXTURE_2D == tex_tgt) { + rx = rx / (GLfloat)width; + ry = ry / (GLfloat)height; + rxe = rxe / (GLfloat)width; + rye = rye / (GLfloat)height; + } + auto rdx = (GLfloat)crect.x1; + auto rdy = (GLfloat)(ps->root_height - crect.y1); + auto rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1); + auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1); + + // Invert Y if needed, this may not work as expected, though. I + // don't have such a FBConfig to test with. + /*if (ptex && !ptex->y_inverted)*/ { + ry = 1.0f - ry; + rye = 1.0f - rye; + } + + log_warn("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", + ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); + + // log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, + // ry, rxe, rye, + // rdx, rdy, rdxe, rdye); + + glTexCoord2f(rx, ry); + glVertex3f(rdx, rdy, z); + + glTexCoord2f(rxe, ry); + glVertex3f(rdxe, rdy, z); + + glTexCoord2f(rxe, rye); + glVertex3f(rdxe, rdye, z); + + glTexCoord2f(rx, rye); + glVertex3f(rdx, rdye, z); + + } + P_PAINTREG_END(); + } + glUseProgram(0); } @@ -1215,7 +1289,7 @@ bool glx_round_corners_dst(session_t *ps attr_unused, int dx, int dy, int width, glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(tex_tgt, 0); glDisable(tex_tgt); - glDisable(GL_BLEND); + //glDisable(GL_BLEND); if (have_scissors) glEnable(GL_SCISSOR_TEST); if (have_stencil) @@ -1263,9 +1337,9 @@ bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, /** * @brief Render a region with texture data. */ -bool 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 argb, bool neg, - const region_t *reg_tgt, const glx_prog_main_t *pprogram) { +bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const glx_texture_t *ptex, + int x, int y, int dx, int dy, int width, int height, int z, double opacity, bool argb, + bool neg, int cr attr_unused, const region_t *reg_tgt, const glx_prog_main_t *pprogram) { if (!ptex || !ptex->texture) { log_error("Missing texture."); return false; diff --git a/src/opengl.h b/src/opengl.h index c71eb78458..32688e132c 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -87,8 +87,8 @@ typedef struct _glx_texture { bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, GLfloat factor, const region_t *reg_tgt); -bool 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 argb, bool neg, +bool glx_render(session_t *ps, const struct managed_win *w, const glx_texture_t *ptex, int x, int y, int dx, int dy, + int width, int height, int z, double opacity, bool argb, bool neg, int cr, const region_t *reg_tgt, const glx_prog_main_t *pprogram); bool glx_init(session_t *ps, bool need_render); @@ -125,8 +125,8 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst(session_t *ps, int dx, int dy, int width, int height, float z, float cr, - GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); +bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex, int dx, int dy, int width, int height, float z, float cr, + GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); GLuint glx_create_shader(GLenum shader_type, const char *shader_str); diff --git a/src/picom.c b/src/picom.c index 19cab08435..6380f0aed7 100644 --- a/src/picom.c +++ b/src/picom.c @@ -481,7 +481,7 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { } // Update window mode - w->mode = win_calc_mode(w); + w->mode = win_calc_mode(ps, w); // Destroy all reg_ignore above when frame opaque state changes on // SOLID mode diff --git a/src/render.c b/src/render.c index a551654821..0efcd8e8f9 100644 --- a/src/render.c +++ b/src/render.c @@ -245,7 +245,7 @@ uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ return n; } -void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, +void render(session_t *ps, const struct managed_win *w, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram) { switch (ps->o.backend) { @@ -300,8 +300,8 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f } #ifdef CONFIG_OPENGL case BKEND_GLX: - glx_render(ps, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb, - neg, reg_paint, pprogram); + glx_render(ps, w, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb, + neg, cr, reg_paint, pprogram); ps->psglx->z += 1; break; #endif @@ -325,7 +325,7 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); const bool neg = (w && w->invert_color); - render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, + render(ps, w, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg, (w ? w->corner_radius : 0), pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint, #ifdef CONFIG_OPENGL @@ -378,7 +378,7 @@ win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_pic } break; #ifdef CONFIG_OPENGL case BKEND_GLX: - glx_round_corners_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, + glx_round_corners_dst(ps, NULL, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, (float)factor_center, reg_paint, &w->glx_round_cache); break; #endif @@ -543,11 +543,6 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) if (pict != w->paint.pict) free_picture(ps->c, &pict); - // Round the corners - if (w->corner_radius > 0) { - win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); - } - // Dimming the window if needed if (w->dim) { double dim_opacity = ps->o.inactive_dim; @@ -586,6 +581,12 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) default: assert(false); } } + + // Round the corners + if (w->corner_radius > 0) { + log_warn("x:%d y:%d w:%d h:%d", x, y, wid, hei); + win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); + } } extern const char *background_props_str[]; @@ -747,7 +748,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { return; } - render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, + render(ps, w, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL); } @@ -1162,8 +1163,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { else glFlush(); glXWaitX(); - glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width, - ps->root_height, 0, 1.0, false, false, ®ion, NULL); + glx_render(ps, t, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width, + ps->root_height, 0, 1.0, false, false, 0, ®ion, NULL); // falls through case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break; #endif diff --git a/src/render.h b/src/render.h index 07e1e4bd61..4a3e686dc2 100644 --- a/src/render.h +++ b/src/render.h @@ -25,7 +25,7 @@ typedef struct paint { #endif } paint_t; -void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, +void render(session_t *ps, const struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); diff --git a/src/win.c b/src/win.c index d0adc6ccb3..90d8a76f5f 100644 --- a/src/win.c +++ b/src/win.c @@ -561,7 +561,7 @@ bool win_client_has_alpha(const struct managed_win *w) { w->client_pictfmt->direct.alpha_mask; } -winmode_t win_calc_mode(const struct managed_win *w) { +winmode_t win_calc_mode(session_t *ps, const struct managed_win *w) { if (w->opacity < 1.0) { return WMODE_TRANS; } @@ -569,6 +569,10 @@ winmode_t win_calc_mode(const struct managed_win *w) { return WMODE_FRAME_TRANS; } + if (ps->o.backend == BKEND_GLX && w->corner_radius > 0) { + return WMODE_TRANS; + } + if (win_has_alpha(w)) { if (w->client_win == XCB_NONE) { // This is a window not managed by the WM, and it has alpha, @@ -2106,7 +2110,7 @@ void map_win_start(session_t *ps, struct managed_win *w) { } // Update window mode here to check for ARGB windows - w->mode = win_calc_mode(w); + w->mode = win_calc_mode(ps, w); // Detect client window here instead of in add_win() as the client // window should have been prepared at this point diff --git a/src/win.h b/src/win.h index 7cdfa9ced7..24eff2a6e3 100644 --- a/src/win.h +++ b/src/win.h @@ -281,7 +281,7 @@ bool must_use destroy_win_start(session_t *ps, struct win *w); void win_release_images(struct backend_base *base, struct managed_win *w); int win_update_name(session_t *ps, struct managed_win *w); int win_get_role(session_t *ps, struct managed_win *w); -winmode_t attr_pure win_calc_mode(const struct managed_win *w); +winmode_t attr_pure win_calc_mode(session_t *ps, const struct managed_win *w); void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val); void win_set_fade_force(struct managed_win *w, switch_t val); void win_set_focused_force(session_t *ps, struct managed_win *w, switch_t val); From 6c0b19f98dc9937a515058466b11cb89f3b8a977 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Sun, 29 Mar 2020 20:32:12 -0700 Subject: [PATCH 18/38] merged with yshui/compton up to commit 4c22d56 --- src/c2.c | 11 ----------- src/config.c | 1 - src/config.h | 2 -- src/dbus.c | 5 +---- src/event.c | 7 +++---- src/picom.c | 6 ++---- src/win.c | 8 +++----- 7 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/c2.c b/src/c2.c index f5fe5502a0..f03f2b453f 100644 --- a/src/c2.c +++ b/src/c2.c @@ -1028,17 +1028,6 @@ static bool c2_l_postprocess(session_t *ps, c2_l_t *pleaf) { } } - // Enable specific tracking options, if needed by the condition - // TODO: Add track_leader - switch (pleaf->predef) { - // case C2_L_PROUNDED: ps->o.detect_rounded_corners = true; break; - case C2_L_PNAME: - case C2_L_PCLASSG: - case C2_L_PCLASSI: - case C2_L_PROLE: ps->o.track_wdata = true; break; - default: break; - } - // Warn about lower case characters in target name if (pleaf->predef == C2_L_PUNDEFINED) { for (const char *pc = pleaf->tgt; *pc; ++pc) { diff --git a/src/config.c b/src/config.c index b93b216e09..8dd1502f33 100644 --- a/src/config.c +++ b/src/config.c @@ -559,7 +559,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .detect_client_leader = false, .no_ewmh_fullscreen = false, - .track_wdata = false, .track_leader = false, .rounded_corners_blacklist = NULL diff --git a/src/config.h b/src/config.h index 19a48e7a7f..ae0aa97fd0 100644 --- a/src/config.h +++ b/src/config.h @@ -228,8 +228,6 @@ typedef struct options { bool detect_client_leader; // === Calculated === - /// Whether we need to track window name and class. - bool track_wdata; /// Whether we need to track window leaders. bool track_leader; diff --git a/src/dbus.c b/src/dbus.c index b1218281a8..3f0d95020f 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -1040,16 +1040,13 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) { cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool); cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool); cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool); + cdbus_m_opts_get_do(use_damage, cdbus_reply_bool); #ifdef CONFIG_OPENGL cdbus_m_opts_get_do(glx_no_stencil, cdbus_reply_bool); cdbus_m_opts_get_do(glx_no_rebind_pixmap, cdbus_reply_bool); - cdbus_m_opts_get_do(use_damage, cdbus_reply_bool); #endif - cdbus_m_opts_get_stub(track_focus, cdbus_reply_bool, true); - cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool); - cdbus_m_opts_get_do(track_leader, cdbus_reply_bool); #undef cdbus_m_opts_get_do #undef cdbus_m_opts_get_stub diff --git a/src/event.c b/src/event.c index 9f094c0bb5..4a0333848b 100644 --- a/src/event.c +++ b/src/event.c @@ -495,8 +495,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } // If name changes - if (ps->o.track_wdata && - (ps->atoms->aWM_NAME == ev->atom || ps->atoms->a_NET_WM_NAME == ev->atom)) { + if (ps->atoms->aWM_NAME == ev->atom || ps->atoms->a_NET_WM_NAME == ev->atom) { auto w = find_toplevel(ps, ev->window); if (w && win_update_name(ps, w) == 1) { win_on_factor_change(ps, w); @@ -504,7 +503,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } // If class changes - if (ps->o.track_wdata && ps->atoms->aWM_CLASS == ev->atom) { + if (ps->atoms->aWM_CLASS == ev->atom) { auto w = find_toplevel(ps, ev->window); if (w) { win_get_class(ps, w); @@ -513,7 +512,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } // If role changes - if (ps->o.track_wdata && ps->atoms->aWM_WINDOW_ROLE == ev->atom) { + if (ps->atoms->aWM_WINDOW_ROLE == ev->atom) { auto w = find_toplevel(ps, ev->window); if (w && 1 == win_get_role(ps, w)) { win_on_factor_change(ps, w); diff --git a/src/picom.c b/src/picom.c index 6380f0aed7..b036ed60cd 100644 --- a/src/picom.c +++ b/src/picom.c @@ -309,11 +309,9 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) { } // Check if it's a mapped client window - if (WIN_EVMODE_CLIENT == mode || + if (mode == WIN_EVMODE_CLIENT || ((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) { - if (ps->o.frame_opacity > 0 || ps->o.track_wdata || ps->track_atom_lst || - ps->o.detect_client_opacity) - evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; + evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; } return evmask; diff --git a/src/win.c b/src/win.c index 90d8a76f5f..ff271a9851 100644 --- a/src/win.c +++ b/src/win.c @@ -1036,11 +1036,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client) win_update_leader(ps, w); // Get window name and class if we are tracking them - if (ps->o.track_wdata) { - win_update_name(ps, w); - win_get_class(ps, w); - win_get_role(ps, w); - } + win_update_name(ps, w); + win_get_class(ps, w); + win_get_role(ps, w); // Update everything related to conditions win_on_factor_change(ps, w); From f48a7c6914fd6070a871464f8b26818951ad51ec Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 12:20:21 -0700 Subject: [PATCH 19/38] rounded corners with glx: almost there... --- src/opengl.c | 415 ++++++++++++++++++++++++++++++++------------------- src/opengl.h | 13 +- src/render.c | 24 +-- src/render.h | 2 +- 4 files changed, 287 insertions(+), 167 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 5364a3bfbe..b1e3ed6062 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -99,10 +99,9 @@ bool glx_init(session_t *ps, bool need_render) { ppass->unifm_offset_y = -1; } - ps->psglx->round_passes = ccalloc(1, glx_round_pass_t); - { - glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; - ppass->unifm_factor_center = -1; + ps->psglx->round_passes = ccalloc(2, glx_round_pass_t); + for (int i = 0; i < 2; ++i) { + glx_round_pass_t *ppass = &ps->psglx->round_passes[i]; ppass->unifm_radius = -1; ppass->unifm_texcoord = -1; ppass->unifm_texsize = -1; @@ -252,14 +251,14 @@ void glx_destroy(session_t *ps) { } free(ps->psglx->blur_passes); - { - glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + for (int i = 0; i < 2; ++i) { + glx_round_pass_t *ppass = &ps->psglx->round_passes[i]; if (ppass->frag_shader) glDeleteShader(ppass->frag_shader); if (ppass->prog) glDeleteProgram(ppass->prog); - free(ps->psglx->round_passes); } + free(ps->psglx->round_passes); glx_free_prog_main(&ps->glx_prog_win); @@ -435,6 +434,68 @@ bool glx_init_blur(session_t *ps) { return true; } +static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, + const char *PREFIX_STR, const char* SHADER_STR, + const char *extension, const char *sampler_type, const char *texture_func) { + + // Build rounded corners shader + { + auto len = strlen(PREFIX_STR) + strlen(extension) + + strlen(sampler_type)*2 + strlen(texture_func)*2 + + strlen(SHADER_STR) + 1; + char *shader_str = calloc(len, sizeof(char)); + if (!shader_str) { + log_error("Failed to allocate %zd bytes for shader string.", len); + return false; + } + + char *pc = shader_str; + sprintf(pc, PREFIX_STR, extension, sampler_type, sampler_type, texture_func, texture_func); + pc += strlen(pc); + assert(strlen(shader_str) < len); + + sprintf(pc, SHADER_STR); + assert(strlen(shader_str) < len); +#ifdef DEBUG_GLX + log_debug("Generated rounded corners shader:\n%s\n", shader_str); +#endif + + log_warn("Generated rounded corners shader:\n%s\n", shader_str); + ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); + free(shader_str); + + if (!ppass->frag_shader) { + log_error("Failed to create rounded corners fragment shader."); + return false; + } + + // Build program + ppass->prog = gl_create_program(&ppass->frag_shader, 1); + if (!ppass->prog) { + log_error("Failed to create GLSL program."); + return false; + } + + // Get uniform addresses +#define P_GET_UNIFM_LOC(name, target) \ +{ \ + ppass->target = glGetUniformLocation(ppass->prog, name); \ + if (ppass->target < 0) { \ + log_error("Failed to get location of rounded corners uniform '" name \ + "'. Might be troublesome." \ + ); \ + } \ +} + P_GET_UNIFM_LOC("u_radius", unifm_radius); + P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); + P_GET_UNIFM_LOC("u_texsize", unifm_texsize); + P_GET_UNIFM_LOC("u_resolution", unifm_resolution); +#undef P_GET_UNIFM_LOC + } + + return true; +} + /** * Initialize GLX rounded corners filter. */ @@ -451,14 +512,12 @@ bool glx_init_rounded_corners(session_t *ps) { static const char *FRAG_SHADER_PREFIX = "#version 110\n" "%s" // extensions - "uniform float offset_x;\n" - "uniform float offset_y;\n" - "uniform float factor_center;\n" "uniform float u_radius;\n" "uniform vec2 u_texcoord;\n" "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect + "uniform %s tex_bg;\n" // sampler2D | sampler2DRect "\n" "// https://www.shadertoy.com/view/ldfSDj\n" "float udRoundBox( vec2 p, vec2 b, float r )\n" @@ -467,25 +526,24 @@ bool glx_init_rounded_corners(session_t *ps) { "}\n\n" "void main()\n" "{\n" - " vec4 col = %s(tex_scr, vec2(gl_TexCoord[0].x, gl_TexCoord[0].y)) * factor_center;\n" - " //vec4 col = vec4(1.0, 1.0, 1.0, 1.0);\n" - "\n"; - - // Fragment shader (round corners) - static const char *FRAG_SHADER_ROUND_CORNERS = + " vec4 col_scr = %s(tex_scr, gl_TexCoord[0].st);\n" + " vec4 col_bg = %s(tex_bg, gl_TexCoord[0].st);\n" " vec2 halfres = 0.5 * u_texsize.xy;\n" " vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);\n" "\n" " // compute box\n" " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres, u_radius );\n" - "\n" + "\n"; + + // Fragment shader (round corners) + static const char *FRAG_SHADER_ROUND_CORNERS_PRE = " // colorize (red / black )\n" " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " vec4 c = mix( col, vec4(1.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( col_scr, vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" - " //if ( c == vec4(0.0,1.0,0.0,0.0) ) discard; else\n" + " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " gl_FragColor = vec4( c );\n" " //gl_FragColor = vec4( c.rgb, 0.0 );\n" " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" @@ -494,6 +552,19 @@ bool glx_init_rounded_corners(session_t *ps) { " //gl_FragColor = gl_Color;\n" " //gl_FragColor = col;\n" "}\n"; + + // Fragment shader (round corners) + static const char *FRAG_SHADER_ROUND_CORNERS_POST = + " // colorize (red / black )\n" + " //vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" + "\n" + " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" + " //if ( c == vec4(1.0,1.0,1.0,1.0) ) discard; else\n" + " gl_FragColor = vec4( c );\n" + " //gl_FragColor = vec4(0.2, 0.2, 0.2, 0.2);\n" + "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; const char *sampler_type = (use_texture_rect ? "sampler2DRect": "sampler2D"); @@ -507,66 +578,27 @@ bool glx_init_rounded_corners(session_t *ps) { extension = strdup(""); } - // Build rounded corners shader - glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; - { - auto len = strlen(FRAG_SHADER_PREFIX) + strlen(extension) - + strlen(sampler_type) + strlen(texture_func) - + strlen(FRAG_SHADER_ROUND_CORNERS) + 1; - char *shader_str = calloc(len, sizeof(char)); - if (!shader_str) { - log_error("Failed to allocate %zd bytes for shader string.", len); - return false; - } + if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[0], + FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_PRE, + extension, sampler_type, texture_func)) { - char *pc = shader_str; - sprintf(pc, FRAG_SHADER_PREFIX, extension, sampler_type, texture_func, texture_func); - pc += strlen(pc); - assert(strlen(shader_str) < len); - - sprintf(pc, FRAG_SHADER_ROUND_CORNERS); - assert(strlen(shader_str) < len); -#ifdef DEBUG_GLX - log_debug("Generated rounded corners shader:\n%s\n", shader_str); -#endif - - log_warn("Generated rounded corners shader:\n%s\n", shader_str); - ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); - free(shader_str); - - if (!ppass->frag_shader) { - log_error("Failed to create rounded corners fragment shader."); - free(extension); - free(lc_numeric_old); - return false; - } + log_error("Failed to create rounded corners fragment shader PRE."); + setlocale(LC_NUMERIC, lc_numeric_old); + free(lc_numeric_old); + free(extension); + return false; + } - // Build program - ppass->prog = gl_create_program(&ppass->frag_shader, 1); - if (!ppass->prog) { - log_error("Failed to create GLSL program."); - free(extension); - free(lc_numeric_old); - return false; - } + if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[1], + FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_POST, + extension, sampler_type, texture_func)) { - // Get uniform addresses -#define P_GET_UNIFM_LOC(name, target) \ - { \ - ppass->target = glGetUniformLocation(ppass->prog, name); \ - if (ppass->target < 0) { \ - log_error("Failed to get location of rounded corners uniform '" name \ - "'. Might be troublesome." \ - ); \ - } \ - } - P_GET_UNIFM_LOC("factor_center", unifm_factor_center); - P_GET_UNIFM_LOC("u_radius", unifm_radius); - P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); - P_GET_UNIFM_LOC("u_texsize", unifm_texsize); - P_GET_UNIFM_LOC("u_resolution", unifm_resolution); -#undef P_GET_UNIFM_LOC - } + log_error("Failed to create rounded corners fragment shader POST."); + setlocale(LC_NUMERIC, lc_numeric_old); + free(lc_numeric_old); + free(extension); + return false; + } free(extension); @@ -1054,11 +1086,22 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, } -bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, +static void bind_sampler_to_unit_with_texture(GLuint prog, GLchar const * const sampler_name, GLuint texture_unit, GLenum tex_tgt, GLuint texture) +{ + glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(tex_tgt, texture); + GLint loc_sampler = glGetUniformLocation(prog, sampler_name); + glUniform1i(loc_sampler, (GLint)texture_unit); +} + + +bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, int shader_idx, int dx, int dy, int width, int height, float z, float cr, - GLfloat factor_center, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { + const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { + assert(shader_idx >= 0 && shader_idx <= 1); assert(ps->psglx->round_passes[0].prog); + assert(ps->psglx->round_passes[1].prog); const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; @@ -1086,12 +1129,6 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, pbc->textures[0] = glx_gen_texture(tex_tgt, mwidth, mheight); GLuint tex_scr = pbc->textures[0]; - // Adjustments calling from glx_render() - /*if (ptex) { - tex_tgt = ptex->target; - tex_scr = ptex->texture; - }*/ - pbc->width = mwidth; pbc->height = mheight; @@ -1112,8 +1149,14 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, texfac_y /= (GLfloat)mheight; } + // Paint it back { - const glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + } + + { + const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; assert(ppass->prog); assert(tex_scr); @@ -1129,9 +1172,9 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, { // Control blending with src - glDisable(GL_BLEND); + //glDisable(GL_BLEND); //glEnable(GL_BLEND); - //glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_ZERO, GL_ONE); @@ -1160,10 +1203,13 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, } - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); - if (ppass->unifm_factor_center >= 0) - glUniform1f(ppass->unifm_factor_center, factor_center); + + bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); + //bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 1, tex_tgt, pbc->textures[1]); + //if (ptex) { bind_sampler_to_unit_with_texture(ppass->prog, "tex_bg", 1, ptex->target, ptex->texture); } + if (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); if (ppass->unifm_texcoord >= 0) @@ -1173,64 +1219,30 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); - /*P_PAINTREG_START(crect) { - auto rx = (GLfloat)(crect.x1 - mdx) * texfac_x; - auto ry = (GLfloat)(mheight - (crect.y1 - mdy)) * texfac_y; - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1) * texfac_x; - auto rye = ry - (GLfloat)(crect.y2 - crect.y1) * texfac_y; - auto rdx = (GLfloat)(crect.x1 - mdx); - auto rdy = (GLfloat)(mheight - crect.y1 + mdy); - { - rdx = (GLfloat)crect.x1; - rdy = (GLfloat)(ps->root_height - crect.y1); - } - auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); - -#ifdef DEBUG_GLX - log_debug("Rounded corner Pass: %f, %f, %f, %f -> %f, %f, %f, %f", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); -#endif - - //log_warn("Rounded corner Pass: %f, %f, %f, %f, %f, %f -> %f, %f, %f, %f", - // texfac_x, texfac_y, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); - - glTexCoord2f(rx, ry); - glVertex3f(rdx, rdy, z); - - glTexCoord2f(rxe, ry); - glVertex3f(rdxe, rdy, z); - - glTexCoord2f(rxe, rye); - glVertex3f(rdxe, rdye, z); - - glTexCoord2f(rx, rye); - glVertex3f(rdx, rdye, z); - } - P_PAINTREG_END();*/ - - /*P_PAINTREG_START(crect) { - // XXX what does all of these variables mean? - auto rdx = (GLfloat)crect.x1; - auto rdy = (GLfloat)(ps->root_height - crect.y1); - auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); + // Painting + /*if (shader_idx == 1) { + P_PAINTREG_START(crect) { + // XXX what does all of these variables mean? + auto rdx = (GLfloat)crect.x1; + auto rdy = (GLfloat)(ps->root_height - crect.y1); + auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); + auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); #ifdef DEBUG_GLX - log_debug("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); + log_debug("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); #endif - log_warn("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", - crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); + log_warn("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", + crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); - glVertex3f(rdx, rdy, z); - glVertex3f(rdxe, rdy, z); - glVertex3f(rdxe, rdye,z); - glVertex3f(rdx, rdye, z); - } - P_PAINTREG_END();*/ + glVertex3f(rdx, rdy, z); + glVertex3f(rdxe, rdy, z); + glVertex3f(rdxe, rdye,z); + glVertex3f(rdx, rdye, z); + } + P_PAINTREG_END(); - // Painting - { + } else*/ { P_PAINTREG_START(crect) { // XXX explain these variables auto rx = (GLfloat)(crect.x1 - dx); @@ -1252,7 +1264,8 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, // Invert Y if needed, this may not work as expected, though. I // don't have such a FBConfig to test with. - /*if (ptex && !ptex->y_inverted)*/ { + //if (ptex && !ptex->y_inverted) { + if (shader_idx == 0) { ry = 1.0f - ry; rye = 1.0f - rye; } @@ -1304,6 +1317,96 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, return ret; } +bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader_idx, + int dx, int dy, int width, int height, float z, float cr, + const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { + + assert(shader_idx >= 0 && shader_idx <= 1); + assert(ps->psglx->round_passes[0].prog); + assert(ps->psglx->round_passes[1].prog); + bool ret = false; + + log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) z(%.2f)", dx, dy, width, height, ps->root_width, ps->root_height, z); + + { + const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; + assert(ppass->prog); + + glUseProgram(ppass->prog); + + if (ppass->unifm_radius >= 0) + glUniform1f(ppass->unifm_radius, cr); + if (ppass->unifm_texcoord >= 0) + glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); + if (ppass->unifm_texsize >= 0) + glUniform2f(ppass->unifm_texsize, (float)width, (float)height); + if (ppass->unifm_resolution >= 0) + glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); + + // Painting + { + P_PAINTREG_START(crect) { + // XXX explain these variables + auto rx = (GLfloat)(crect.x1 - dx); + auto ry = (GLfloat)(crect.y1 - dy); + auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); + auto rye = ry + (GLfloat)(crect.y2 - crect.y1); + // Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] + // [0-1] Thanks to amonakov for pointing out! + if (GL_TEXTURE_2D == ptex->target) { + rx = rx / (GLfloat)width; + ry = ry / (GLfloat)height; + rxe = rxe / (GLfloat)width; + rye = rye / (GLfloat)height; + } + auto rdx = (GLfloat)crect.x1; + auto rdy = (GLfloat)(ps->root_height - crect.y1); + auto rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1); + auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1); + + // Invert Y if needed, this may not work as expected, though. I + // don't have such a FBConfig to test with. + //if (ptex && !ptex->y_inverted) { + if (shader_idx == 0) { + ry = 1.0f - ry; + rye = 1.0f - rye; + } + + log_warn("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", + ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); + + // log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, + // ry, rxe, rye, + // rdx, rdy, rdxe, rdye); + + glTexCoord2f(rx, ry); + glVertex3f(rdx, rdy, z); + + glTexCoord2f(rxe, ry); + glVertex3f(rdxe, rdy, z); + + glTexCoord2f(rxe, rye); + glVertex3f(rdxe, rdye, z); + + glTexCoord2f(rx, rye); + glVertex3f(rdx, rdye, z); + + } + P_PAINTREG_END(); + } + + glUseProgram(0); + } + + ret = true; + + //glBindFramebuffer(GL_FRAMEBUFFER, 0); + + gl_check_err(); + + return ret; +} + bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, GLfloat factor, const region_t *reg_tgt) { // It's possible to dim in glx_render(), but it would be over-complicated @@ -1337,7 +1440,7 @@ bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, /** * @brief Render a region with texture data. */ -bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const glx_texture_t *ptex, +bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_texture_t *ptex, int x, int y, int dx, int dy, int width, int height, int z, double opacity, bool argb, bool neg, int cr attr_unused, const region_t *reg_tgt, const glx_prog_main_t *pprogram) { if (!ptex || !ptex->texture) { @@ -1347,13 +1450,14 @@ bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const gl const bool has_prog = pprogram && pprogram->prog; bool dual_texture = false; + GLuint tex_scr = ptex->texture; // It's required by legacy versions of OpenGL to enable texture target // before specifying environment. Thanks to madsy for telling me. glEnable(ptex->target); // Enable blending if needed - if (opacity < 1.0 || argb) { + if (opacity < 1.0 || argb || cr > 0) { glEnable(GL_BLEND); @@ -1363,7 +1467,18 @@ bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const gl // This is all weird, but X Render is using premultiplied ARGB format, and // we need to use those things to correct it. Thanks to derhass for help. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glColor4d(opacity, opacity, opacity, opacity); + if (cr == 0) { + glColor4d(opacity, opacity, opacity, opacity); + } else { + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + glx_round_corners_dst2(ps, ptex, 1, dx, dy, to_u16_checked(w->widthb), to_u16_checked(w->heightb), + (float)ps->psglx->z - 0.5f, (float)cr, reg_tgt, &w->glx_round_cache); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + //glDisable(GL_BLEND); + glColor4f(0.5f, 0.5f, 0.5f, 0.5f); + //glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + //glColor4f(0.0f, 0.0f, 0.0f, 0.0f); + } } if (!has_prog) { @@ -1400,7 +1515,7 @@ bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const gl // Texture stage 1 glActiveTexture(GL_TEXTURE1); glEnable(ptex->target); - glBindTexture(ptex->target, ptex->texture); + glBindTexture(ptex->target, tex_scr); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); @@ -1456,10 +1571,10 @@ bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const gl // dx, dy, ptex->width, ptex->height, z); // Bind texture - glBindTexture(ptex->target, ptex->texture); + glBindTexture(ptex->target, tex_scr); if (dual_texture) { glActiveTexture(GL_TEXTURE1); - glBindTexture(ptex->target, ptex->texture); + glBindTexture(ptex->target, tex_scr); glActiveTexture(GL_TEXTURE0); } @@ -1486,7 +1601,7 @@ bool glx_render(session_t *ps, const struct managed_win *w attr_unused, const gl // Invert Y if needed, this may not work as expected, though. I // don't have such a FBConfig to test with. - if (!ptex->y_inverted) { + if (!ptex->y_inverted || tex_scr != ptex->texture) { ry = 1.0f - ry; rye = 1.0f - rye; } diff --git a/src/opengl.h b/src/opengl.h index 32688e132c..326a5e9595 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -45,8 +45,6 @@ typedef struct { GLuint frag_shader; /// GLSL program for rounded corners. GLuint prog; - /// Location of uniform "factor_center" in rounded-corners GLSL program. - GLint unifm_factor_center; /// Location of uniform "radius" in rounded-corners GLSL program. GLint unifm_radius; /// Location of uniform "texcoord" in rounded-corners GLSL program. @@ -87,7 +85,7 @@ typedef struct _glx_texture { bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z, GLfloat factor, const region_t *reg_tgt); -bool glx_render(session_t *ps, const struct managed_win *w, const glx_texture_t *ptex, int x, int y, int dx, int dy, +bool glx_render(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int x, int y, int dx, int dy, int width, int height, int z, double opacity, bool argb, bool neg, int cr, const region_t *reg_tgt, const glx_prog_main_t *pprogram); @@ -125,8 +123,13 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex, int dx, int dy, int width, int height, float z, float cr, - GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); +bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex, int shader_idx, + int dx, int dy, int width, int height, float z, float cr, + const region_t *reg_tgt, glx_blur_cache_t *pbc); + +bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader_idx, + int dx, int dy, int width, int height, float z, float cr, + const region_t *reg_tgt, glx_blur_cache_t *pbc); GLuint glx_create_shader(GLenum shader_type, const char *shader_str); diff --git a/src/render.c b/src/render.c index 0efcd8e8f9..5017eb3610 100644 --- a/src/render.c +++ b/src/render.c @@ -245,7 +245,7 @@ uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ return n; } -void render(session_t *ps, const struct managed_win *w, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, +void render(session_t *ps, struct managed_win *w, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram) { switch (ps->o.backend) { @@ -316,7 +316,7 @@ void render(session_t *ps, const struct managed_win *w, int x, int y, int dx, in } static inline void -paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei, +paint_region(session_t *ps, struct managed_win *w, int x, int y, int wid, int hei, double opacity, const region_t *reg_paint, xcb_render_picture_t pict) { const int dx = (w ? w->g.x : 0) + x; const int dy = (w ? w->g.y : 0) + y; @@ -362,15 +362,13 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { * */ static inline void -win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_picture_t tgt_buffer attr_unused, - const region_t *reg_paint) { +win_round_corners(session_t *ps, struct managed_win *w, int shader_idx, float cr, + xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { const int16_t x = w->g.x; const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); - double factor_center = 1.0; - switch (ps->o.backend) { case BKEND_XRENDER: case BKEND_XR_GLX_HYBRID: { @@ -378,8 +376,8 @@ win_round_corners(session_t *ps, struct managed_win *w, float cr, xcb_render_pic } break; #ifdef CONFIG_OPENGL case BKEND_GLX: - glx_round_corners_dst(ps, NULL, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, - (float)factor_center, reg_paint, &w->glx_round_cache); + glx_round_corners_dst(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, + (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); break; #endif default: assert(0); @@ -583,10 +581,14 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) } // Round the corners - if (w->corner_radius > 0) { + /*const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); + if (argb && w->corner_radius > 0) { log_warn("x:%d y:%d w:%d h:%d", x, y, wid, hei); - win_round_corners(ps, w, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); - } + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + win_round_corners(ps, w, 0, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); + //glDisable(GL_BLEND); + }*/ } extern const char *background_props_str[]; diff --git a/src/render.h b/src/render.h index 4a3e686dc2..ced66d40dd 100644 --- a/src/render.h +++ b/src/render.h @@ -25,7 +25,7 @@ typedef struct paint { #endif } paint_t; -void render(session_t *ps, const struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, +void render(session_t *ps, struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); From 3f0286fe07366523c3b2be194ce3e86c34a1d048 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 18:37:36 -0700 Subject: [PATCH 20/38] rounded corners progress... --- src/opengl.c | 26 +++++++++----------------- src/opengl.h | 4 ++-- src/render.c | 34 ++++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index b1e3ed6062..c7379ba07c 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -556,8 +556,8 @@ bool glx_init_rounded_corners(session_t *ps) { // Fragment shader (round corners) static const char *FRAG_SHADER_ROUND_CORNERS_POST = " // colorize (red / black )\n" - " //vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" - " vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" "\n" " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" @@ -1095,7 +1095,7 @@ static void bind_sampler_to_unit_with_texture(GLuint prog, GLchar const * const } -bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, int shader_idx, +bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { @@ -1169,7 +1169,6 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, if (have_stencil) glEnable(GL_STENCIL_TEST); - { // Control blending with src //glDisable(GL_BLEND); @@ -1317,7 +1316,7 @@ bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex attr_unused, return ret; } -bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { @@ -1332,6 +1331,9 @@ bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; assert(ppass->prog); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + glUseProgram(ppass->prog); if (ppass->unifm_radius >= 0) @@ -1396,6 +1398,7 @@ bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader } glUseProgram(0); + glDisable(GL_BLEND); } ret = true; @@ -1467,18 +1470,7 @@ bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_text // This is all weird, but X Render is using premultiplied ARGB format, and // we need to use those things to correct it. Thanks to derhass for help. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - if (cr == 0) { - glColor4d(opacity, opacity, opacity, opacity); - } else { - glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); - glx_round_corners_dst2(ps, ptex, 1, dx, dy, to_u16_checked(w->widthb), to_u16_checked(w->heightb), - (float)ps->psglx->z - 0.5f, (float)cr, reg_tgt, &w->glx_round_cache); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glDisable(GL_BLEND); - glColor4f(0.5f, 0.5f, 0.5f, 0.5f); - //glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - //glColor4f(0.0f, 0.0f, 0.0f, 0.0f); - } + glColor4d(opacity, opacity, opacity, opacity); } if (!has_prog) { diff --git a/src/opengl.h b/src/opengl.h index 326a5e9595..68b011a77d 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -123,11 +123,11 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst2(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc); diff --git a/src/render.c b/src/render.c index 5017eb3610..6ec639af5f 100644 --- a/src/render.c +++ b/src/render.c @@ -369,6 +369,8 @@ win_round_corners(session_t *ps, struct managed_win *w, int shader_idx, float cr const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); + log_warn("x:%d y:%d w:%d h:%d", x, y, wid, hei); + switch (ps->o.backend) { case BKEND_XRENDER: case BKEND_XR_GLX_HYBRID: { @@ -376,8 +378,13 @@ win_round_corners(session_t *ps, struct managed_win *w, int shader_idx, float cr } break; #ifdef CONFIG_OPENGL case BKEND_GLX: - glx_round_corners_dst(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, - (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); + if (shader_idx == 1) { + glx_round_corners_dst1(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, + (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); + } else { + glx_round_corners_dst0(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, + (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); + } break; #endif default: assert(0); @@ -579,16 +586,6 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) default: assert(false); } } - - // Round the corners - /*const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend)); - if (argb && w->corner_radius > 0) { - log_warn("x:%d y:%d w:%d h:%d", x, y, wid, hei); - //glEnable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - win_round_corners(ps, w, 0, (float)w->corner_radius, ps->tgt_buffer.pict, reg_paint); - //glDisable(GL_BLEND); - }*/ } extern const char *background_props_str[]; @@ -1006,7 +1003,12 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Whether this is beneficial is to be determined XXX for (auto w = t; w; w = w->prev_trans) { region_t bshape_no_corners = win_get_bounding_shape_global_by_val(w, false); - region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true); + region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true); + + // Round corners + //if (w->corner_radius > 0) { + // win_round_corners(ps, w, 0, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } + // Painting shadow if (w->shadow) { // Lazy shadow building @@ -1062,12 +1064,13 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Remember, reg_ignore is the union of all windows above the current // window. pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); - pixman_region32_intersect(®_tmp, ®_tmp, &bshape_corners); + pixman_region32_intersect(®_tmp, ®_tmp, &bshape_no_corners); pixman_region32_fini(&bshape_corners); pixman_region32_fini(&bshape_no_corners); if (pixman_region32_not_empty(®_tmp)) { set_tgt_clip(ps, ®_tmp); + // Blur window background if (w->blur_background && (w->mode == WMODE_TRANS || @@ -1077,6 +1080,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Painting the window paint_one(ps, w, ®_tmp); + + if (w->corner_radius > 0) { + win_round_corners(ps, w, 1, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } } } From 8e62405c37133ea108a57a949c92334c65517240 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 18:42:30 -0700 Subject: [PATCH 21/38] merged with yshui/picom up to commit b109526 --- tests/testcases/common.py | 43 +++++++++++++++++++++++++ tests/testcases/issue239.py | 12 ++----- tests/testcases/issue239_3.py | 17 +++------- tests/testcases/issue239_3_norefresh.py | 17 +++------- 4 files changed, 56 insertions(+), 33 deletions(-) create mode 100644 tests/testcases/common.py diff --git a/tests/testcases/common.py b/tests/testcases/common.py new file mode 100644 index 0000000000..cef5ac372f --- /dev/null +++ b/tests/testcases/common.py @@ -0,0 +1,43 @@ +import xcffib.xproto as xproto +import xcffib.randr as randr +import time +import random +import string +def set_window_name(conn, wid, name): + prop_name = "_NET_WM_NAME" + prop_name = conn.core.InternAtom(True, len(prop_name), prop_name).reply().atom + str_type = "STRING" + str_type = conn.core.InternAtom(True, len(str_type), str_type).reply().atom + conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, prop_name, str_type, 8, len(name), name).check() + +def find_picom_window(conn): + prop_name = "WM_NAME" + prop_name = conn.core.InternAtom(True, len(prop_name), prop_name).reply().atom + setup = conn.get_setup() + root = setup.roots[0].root + windows = conn.core.QueryTree(root).reply() + + ext = xproto.xprotoExtension(conn) + for w in windows.children: + name = ext.GetProperty(False, w, prop_name, xproto.GetPropertyType.Any, 0, (2 ** 32) - 1).reply() + if name.value.buf() == b"picom": + return w + +def trigger_root_configure(conn): + setup = conn.get_setup() + root = setup.roots[0].root + # Xorg sends root ConfigureNotify when we add a new mode to an output + rr = conn(randr.key) + name = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(0, 32)]) + mode_info = randr.ModeInfo.synthetic(id = 0, width = 1000, height = 1000, dot_clock = 0, + hsync_start = 0, hsync_end = 0, htotal = 0, hskew = 0, vsync_start = 0, vsync_end = 0, + vtotal = 0, name_len = len(name), mode_flags = 0) + + reply = rr.CreateMode(root, mode_info, len(name), name).reply() + mode = reply.mode + reply = rr.GetScreenResourcesCurrent(root).reply() + # our xvfb is setup to only have 1 output + output = reply.outputs[0] + rr.AddOutputModeChecked(output, mode).check() + rr.SetCrtcConfig(reply.crtcs[0], reply.timestamp, reply.config_timestamp, 0, 0, mode, randr.Rotation.Rotate_0, 1, [output]).reply() + diff --git a/tests/testcases/issue239.py b/tests/testcases/issue239.py index ac46428027..fe3f636494 100755 --- a/tests/testcases/issue239.py +++ b/tests/testcases/issue239.py @@ -3,6 +3,7 @@ import xcffib.xproto as xproto import xcffib import time +from common import set_window_name conn = xcffib.connect() setup = conn.get_setup() @@ -18,13 +19,7 @@ conn.core.CreateWindowChecked(depth, wid, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check() # Set Window name so it doesn't get a shadow -name = "_NET_WM_NAME" -name_atom = conn.core.InternAtom(True, len(name), name).reply().atom -str_type = "STRING" -str_type_atom = conn.core.InternAtom(True, len(str_type), str_type).reply().atom - -win_name = "NoShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "NoShadow") # Map the window print("mapping") @@ -34,8 +29,7 @@ # Set the Window name so it gets a shadow print("set new name") -win_name = "YesShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "YesShadow") # Unmap the window conn.core.UnmapWindowChecked(wid).check() diff --git a/tests/testcases/issue239_3.py b/tests/testcases/issue239_3.py index c3d6e151af..3bc966113a 100755 --- a/tests/testcases/issue239_3.py +++ b/tests/testcases/issue239_3.py @@ -3,6 +3,7 @@ import xcffib.xproto as xproto import xcffib import time +from common import set_window_name conn = xcffib.connect() setup = conn.get_setup() @@ -17,14 +18,8 @@ # Create a window conn.core.CreateWindowChecked(depth, wid, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check() -# Set Window name so it doesn't get a shadow -name = "_NET_WM_NAME" -name_atom = conn.core.InternAtom(True, len(name), name).reply().atom -str_type = "STRING" -str_type_atom = conn.core.InternAtom(True, len(str_type), str_type).reply().atom - -win_name = "YesShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +# Set Window name so it gets a shadow +set_window_name(conn, wid, "YesShadow") # Map the window print("mapping") @@ -33,15 +28,13 @@ time.sleep(0.5) print("set new name") -win_name = "NoShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "NoShadow") time.sleep(0.5) # Set the Window name so it gets a shadow print("set new name") -win_name = "YesShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "YesShadow") time.sleep(0.5) diff --git a/tests/testcases/issue239_3_norefresh.py b/tests/testcases/issue239_3_norefresh.py index 9e9bc2f7c7..edcf1c2300 100755 --- a/tests/testcases/issue239_3_norefresh.py +++ b/tests/testcases/issue239_3_norefresh.py @@ -3,6 +3,7 @@ import xcffib.xproto as xproto import xcffib import time +from common import set_window_name conn = xcffib.connect() setup = conn.get_setup() @@ -17,14 +18,8 @@ # Create a window conn.core.CreateWindowChecked(depth, wid, root, 0, 0, 100, 100, 0, xproto.WindowClass.InputOutput, visual, 0, []).check() -# Set Window name so it doesn't get a shadow -name = "_NET_WM_NAME" -name_atom = conn.core.InternAtom(True, len(name), name).reply().atom -str_type = "STRING" -str_type_atom = conn.core.InternAtom(True, len(str_type), str_type).reply().atom - -win_name = "YesShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +# Set Window name so it gets a shadow +set_window_name(conn, wid, "YesShadow") # Map the window print("mapping") @@ -33,13 +28,11 @@ time.sleep(0.5) print("set new name") -win_name = "NoShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "NoShadow") # Set the Window name so it gets a shadow print("set new name") -win_name = "YesShadow" -conn.core.ChangePropertyChecked(xproto.PropMode.Replace, wid, name_atom, str_type_atom, 8, len(win_name), win_name).check() +set_window_name(conn, wid, "YesShadow") time.sleep(0.5) From addfddea642c7af2a47c5eab8758f0f39619348f Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 20:41:28 -0700 Subject: [PATCH 22/38] temp commit before changing lots of code --- src/opengl.c | 52 +++++++++++++++------------------------------------- src/render.c | 20 +++++++++----------- 2 files changed, 24 insertions(+), 48 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index c7379ba07c..d081e2dc3b 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -536,10 +536,11 @@ bool glx_init_rounded_corners(session_t *ps) { "\n"; // Fragment shader (round corners) + // dst0 shader static const char *FRAG_SHADER_ROUND_CORNERS_PRE = " // colorize (red / black )\n" " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " vec4 c = mix( col_scr, vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( col_scr, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" @@ -554,11 +555,12 @@ bool glx_init_rounded_corners(session_t *ps) { "}\n"; // Fragment shader (round corners) + // dst1 shader static const char *FRAG_SHADER_ROUND_CORNERS_POST = " // colorize (red / black )\n" - " vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" "\n" " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " //if ( c == vec4(1.0,1.0,1.0,1.0) ) discard; else\n" @@ -1169,44 +1171,20 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused if (have_stencil) glEnable(GL_STENCIL_TEST); - { - // Control blending with src - //glDisable(GL_BLEND); - //glEnable(GL_BLEND); - //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_ZERO, GL_ONE); - - // Needed for handling opacity of ARGB texture - //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - // This is all weird, but X Render is using premultiplied ARGB format, and - // we need to use those things to correct it. Thanks to derhass for help. - //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - /*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);*/ - } + // Control blending with src + glDisable(GL_BLEND); + //glEnable(GL_BLEND); + //glBlendFunc(GL_ONE, GL_ZERO_MINUS_SRC_ALPHA); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glBlendFunc(GL_ZERO, GL_SRC_ALPHA); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); - //bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 1, tex_tgt, pbc->textures[1]); + //log_warn("ptex:%p %d %d", ptex, ptex ? ptex->target : 0, ptex ? ptex->texture : 0); //if (ptex) { bind_sampler_to_unit_with_texture(ppass->prog, "tex_bg", 1, ptex->target, ptex->texture); } if (ppass->unifm_radius >= 0) @@ -1293,6 +1271,7 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused } glUseProgram(0); + glDisable(GL_BLEND); } ret = true; @@ -1301,7 +1280,6 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(tex_tgt, 0); glDisable(tex_tgt); - //glDisable(GL_BLEND); if (have_scissors) glEnable(GL_SCISSOR_TEST); if (have_stencil) diff --git a/src/render.c b/src/render.c index 6ec639af5f..cbdaf1b6b8 100644 --- a/src/render.c +++ b/src/render.c @@ -362,8 +362,8 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { * */ static inline void -win_round_corners(session_t *ps, struct managed_win *w, int shader_idx, float cr, - xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { +win_round_corners(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, + float cr, xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { const int16_t x = w->g.x; const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); @@ -379,10 +379,10 @@ win_round_corners(session_t *ps, struct managed_win *w, int shader_idx, float cr #ifdef CONFIG_OPENGL case BKEND_GLX: if (shader_idx == 1) { - glx_round_corners_dst1(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, + glx_round_corners_dst1(ps, ptex, shader_idx, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); } else { - glx_round_corners_dst0(ps, (w ? w->paint.ptex : ps->root_tile_paint.ptex), shader_idx, x, y, wid, hei, + glx_round_corners_dst0(ps, ptex, shader_idx, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); } break; @@ -437,7 +437,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) log_error("Window %#010x is missing painting data.", w->base.id); return; } - + const int x = w->g.x; const int y = w->g.y; const uint16_t wid = to_u16_checked(w->widthb); @@ -1005,10 +1005,6 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { region_t bshape_no_corners = win_get_bounding_shape_global_by_val(w, false); region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true); - // Round corners - //if (w->corner_radius > 0) { - // win_round_corners(ps, w, 0, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } - // Painting shadow if (w->shadow) { // Lazy shadow building @@ -1064,7 +1060,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Remember, reg_ignore is the union of all windows above the current // window. pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); - pixman_region32_intersect(®_tmp, ®_tmp, &bshape_no_corners); + pixman_region32_intersect(®_tmp, ®_tmp, &bshape_corners); pixman_region32_fini(&bshape_corners); pixman_region32_fini(&bshape_no_corners); @@ -1081,8 +1077,10 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Painting the window paint_one(ps, w, ®_tmp); + // Round window corners if (w->corner_radius > 0) { - win_round_corners(ps, w, 1, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } + win_round_corners(ps, w, (w ? w->paint.ptex : ps->root_tile_paint.ptex), + 0, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } } } From 491639b3007ad669cd838aa76fbc1d3bfa4fa326 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 21:55:42 -0700 Subject: [PATCH 23/38] need cleanup now, but rounded corners are working with glx --- src/opengl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/opengl.h | 7 +++ src/render.c | 11 ++++- src/win.h | 2 + 4 files changed, 135 insertions(+), 8 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index d081e2dc3b..da8ac4ff62 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -540,7 +540,8 @@ bool glx_init_rounded_corners(session_t *ps) { static const char *FRAG_SHADER_ROUND_CORNERS_PRE = " // colorize (red / black )\n" " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " vec4 c = mix( col_scr, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " //vec4 c = mix( col_scr, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " vec4 c = mix( vec4(0.0,0.0,0.0,0.0), col_scr, smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" " //vec4 c = mix( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" @@ -647,6 +648,112 @@ bool glx_load_prog_main(const char *vshader_str, const char *fshader_str, return true; } +/** + * @brief Release binding of a texture. + */ +void glx_release_texture(session_t *ps attr_unused, glx_texture_t **pptex) { + glx_texture_t *ptex = *pptex; + // Release binding + if (ptex->texture) { + glBindTexture(ptex->target, 0); + glDeleteTextures(1, &ptex->texture); + } + *pptex = NULL; + + gl_check_err(); +} + +/** + * Bind a X pixmap to an OpenGL texture. + */ +bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, + int x, int y, int width attr_unused, int height attr_unused, bool repeat attr_unused) { + if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) + return true; + + glx_texture_t *ptex = *pptex; + + log_warn("Copying xy(%d %d) wh(%d %d)", x, y, width, height); + + // Release pixmap if parameters are inconsistent + if (ptex && ptex->texture && + (ptex->width != width || ptex->height != height)) { + log_warn("Windows size changed old_wh(%d %d) new_wh(%d %d)", ptex->width, ptex->height, width, height); + glx_release_texture(ps, &ptex); + } + + // Allocate structure + if (!ptex) { + static const glx_texture_t GLX_TEX_DEF = { + .texture = 0, + .glpixmap = 0, + .pixmap = 0, + .target = 0, + .width = 0, + .height = 0, + .y_inverted = false, + }; + + ptex = cmalloc(glx_texture_t); + memcpy(ptex, &GLX_TEX_DEF, sizeof(glx_texture_t)); + *pptex = ptex; + + ptex->width = width; + ptex->height = height; + ptex->target = GL_TEXTURE_RECTANGLE; + if (ps->psglx->has_texture_non_power_of_two) + ptex->target = GL_TEXTURE_2D; + } + + // Create texture + if (!ptex->texture) { + log_warn("Generating texture xy(%d %d) wh(%d %d)", x, y, width, height); + GLuint texture = 0; + glGenTextures(1, &texture); + + if (texture) { + glEnable(ptex->target); + glBindTexture(ptex->target, texture); + + glTexParameteri(ptex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(ptex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (repeat) { + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_REPEAT); + } else { + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(ptex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glTexImage2D(ptex->target, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(ptex->target, 0); + //glDisable(ptex->target); + } + + ptex->texture = texture; + } + if (!ptex->texture) { + log_error("Failed to allocate texture."); + return false; + } + + // Read destination pixels into a texture + glEnable(ptex->target); + glBindTexture(ptex->target, ptex->texture); + if (width > 0 && height > 0) + glCopyTexSubImage2D(ptex->target, 0, 0, 0, x, ps->root_height - y - height, width, height); + + // Cleanup + glBindTexture(ptex->target, 0); + glDisable(ptex->target); + + gl_check_err(); + + return true; +} + + /** * Bind a X pixmap to an OpenGL texture. */ @@ -1173,9 +1280,9 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused // Control blending with src - glDisable(GL_BLEND); - //glEnable(GL_BLEND); - //glBlendFunc(GL_ONE, GL_ZERO_MINUS_SRC_ALPHA); + //glDisable(GL_BLEND); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_ZERO, GL_SRC_ALPHA); @@ -1183,9 +1290,11 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused glUseProgram(ppass->prog); - bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); - //log_warn("ptex:%p %d %d", ptex, ptex ? ptex->target : 0, ptex ? ptex->texture : 0); - //if (ptex) { bind_sampler_to_unit_with_texture(ppass->prog, "tex_bg", 1, ptex->target, ptex->texture); } + //bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); + if (ptex) { + log_warn("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); + bind_sampler_to_unit_with_texture(ppass->prog, "tex_bg", 0, ptex->target, ptex->texture); + } if (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); diff --git a/src/opengl.h b/src/opengl.h index 68b011a77d..7c9169d813 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -109,6 +109,11 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, void glx_release_pixmap(session_t *ps, glx_texture_t *ptex); +bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, + int x, int y, int width, int height, bool repeat); + +void glx_release_texture(session_t *ps attr_unused, glx_texture_t **ptex); + void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2); /** @@ -232,6 +237,8 @@ static inline void free_win_res_glx(session_t *ps, struct managed_win *w) { free_paint_glx(ps, &w->shadow_paint); #ifdef CONFIG_OPENGL free_glx_bc(ps, &w->glx_blur_cache); + free_glx_bc(ps, &w->glx_round_cache); + free_texture(ps, &w->glx_texture_bg); free(w->paint.fbcfg); #endif } diff --git a/src/render.c b/src/render.c index cbdaf1b6b8..0e1e5a10f7 100644 --- a/src/render.c +++ b/src/render.c @@ -1066,6 +1066,15 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { if (pixman_region32_not_empty(®_tmp)) { set_tgt_clip(ps, ®_tmp); + + // If rounded corners backup the region first + if (w->corner_radius > 0) { + const int16_t x = w->g.x; + const int16_t y = w->g.y; + const auto wid = to_u16_checked(w->widthb); + const auto hei = to_u16_checked(w->heightb); + glx_bind_texture(ps, &w->glx_texture_bg, x, y, wid, hei, false); + } // Blur window background if (w->blur_background && @@ -1079,7 +1088,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Round window corners if (w->corner_radius > 0) { - win_round_corners(ps, w, (w ? w->paint.ptex : ps->root_tile_paint.ptex), + win_round_corners(ps, w, w->glx_texture_bg, 0, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } } } diff --git a/src/win.h b/src/win.h index 24eff2a6e3..82b1df00cd 100644 --- a/src/win.h +++ b/src/win.h @@ -251,6 +251,8 @@ struct managed_win { /// Textures and FBO background blur use. glx_blur_cache_t glx_blur_cache; glx_blur_cache_t glx_round_cache; + /// Background texture of the window + glx_texture_t *glx_texture_bg; #endif }; From 9879d7fdfd85d8672184f2643396c49d4363ccdd Mon Sep 17 00:00:00 2001 From: bhagwan Date: Mon, 30 Mar 2020 22:53:09 -0700 Subject: [PATCH 24/38] rounded corners code cleanup --- src/opengl.c | 107 +++++++++++++++------------------------------------ src/opengl.h | 2 +- src/render.c | 6 +-- 3 files changed, 34 insertions(+), 81 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index da8ac4ff62..5e5f0df538 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -441,7 +441,7 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, // Build rounded corners shader { auto len = strlen(PREFIX_STR) + strlen(extension) - + strlen(sampler_type)*2 + strlen(texture_func)*2 + + strlen(sampler_type) + strlen(texture_func) + strlen(SHADER_STR) + 1; char *shader_str = calloc(len, sizeof(char)); if (!shader_str) { @@ -450,7 +450,7 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, } char *pc = shader_str; - sprintf(pc, PREFIX_STR, extension, sampler_type, sampler_type, texture_func, texture_func); + sprintf(pc, PREFIX_STR, extension, sampler_type, texture_func); pc += strlen(pc); assert(strlen(shader_str) < len); @@ -460,7 +460,6 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, log_debug("Generated rounded corners shader:\n%s\n", shader_str); #endif - log_warn("Generated rounded corners shader:\n%s\n", shader_str); ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); free(shader_str); @@ -501,8 +500,6 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, */ bool glx_init_rounded_corners(session_t *ps) { - log_warn("glx_init_rounded_corners: cr=%d", ps->o.corner_radius); - { char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane @@ -517,7 +514,6 @@ bool glx_init_rounded_corners(session_t *ps) { "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect - "uniform %s tex_bg;\n" // sampler2D | sampler2DRect "\n" "// https://www.shadertoy.com/view/ldfSDj\n" "float udRoundBox( vec2 p, vec2 b, float r )\n" @@ -527,7 +523,6 @@ bool glx_init_rounded_corners(session_t *ps) { "void main()\n" "{\n" " vec4 col_scr = %s(tex_scr, gl_TexCoord[0].st);\n" - " vec4 col_bg = %s(tex_bg, gl_TexCoord[0].st);\n" " vec2 halfres = 0.5 * u_texsize.xy;\n" " vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);\n" "\n" @@ -538,35 +533,21 @@ bool glx_init_rounded_corners(session_t *ps) { // Fragment shader (round corners) // dst0 shader static const char *FRAG_SHADER_ROUND_CORNERS_PRE = - " // colorize (red / black )\n" - " //vec3 c = mix( vec3(col.r,col.g,col.b), vec3(0.0,1.0,0.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( col_scr, vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " // colorize (transparent mid / opaque corners )\n" " vec4 c = mix( vec4(0.0,0.0,0.0,0.0), col_scr, smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( vec4(1.0,0.0,0.0,0.0), vec4(0.0,1.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" "\n" " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " gl_FragColor = vec4( c );\n" - " //gl_FragColor = vec4( c.rgb, 0.0 );\n" - " //gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" - " //gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n" - " //gl_FragColor = vec4(0.99, 0.99, 0.99, 0.99);\n" - " //gl_FragColor = gl_Color;\n" - " //gl_FragColor = col;\n" "}\n"; // Fragment shader (round corners) // dst1 shader static const char *FRAG_SHADER_ROUND_CORNERS_POST = - " // colorize (red / black )\n" - " //vec4 c = mix( vec4(0.0,0.0,0.0,0.0), vec4(1.0,1.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" - " //vec4 c = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.0,0.0,0.0,0.0), smoothstep(0.0,1.0,b) );\n" + " // colorize (red / green )\n" " vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" "\n" - " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " //if ( c == vec4(1.0,1.0,1.0,1.0) ) discard; else\n" " gl_FragColor = vec4( c );\n" - " //gl_FragColor = vec4(0.2, 0.2, 0.2, 0.2);\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -655,9 +636,11 @@ void glx_release_texture(session_t *ps attr_unused, glx_texture_t **pptex) { glx_texture_t *ptex = *pptex; // Release binding if (ptex->texture) { + //log_info("Deleting texture wh(%d %d)", ptex->width, ptex->height); glBindTexture(ptex->target, 0); glDeleteTextures(1, &ptex->texture); } + free(ptex); *pptex = NULL; gl_check_err(); @@ -673,12 +656,12 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, glx_texture_t *ptex = *pptex; - log_warn("Copying xy(%d %d) wh(%d %d)", x, y, width, height); + //log_trace("Copying xy(%d %d) wh(%d %d)", x, y, width, height); - // Release pixmap if parameters are inconsistent + // Release texture if parameters are inconsistent if (ptex && ptex->texture && (ptex->width != width || ptex->height != height)) { - log_warn("Windows size changed old_wh(%d %d) new_wh(%d %d)", ptex->width, ptex->height, width, height); + log_info("Windows size changed old_wh(%d %d) new_wh(%d %d)", ptex->width, ptex->height, width, height); glx_release_texture(ps, &ptex); } @@ -707,7 +690,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, // Create texture if (!ptex->texture) { - log_warn("Generating texture xy(%d %d) wh(%d %d)", x, y, width, height); + //log_info("Generating texture for xy(%d %d) wh(%d %d)", x, y, width, height); GLuint texture = 0; glGenTextures(1, &texture); @@ -1215,7 +1198,7 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; - log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); + //log_trace("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; @@ -1279,21 +1262,24 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused glEnable(GL_STENCIL_TEST); - // Control blending with src + // Our shader generates a transparent mid section + // with opaque corners copied from the background texture + // We must use blending to get the window pixesl to appear //glDisable(GL_BLEND); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glBlendFunc(GL_ZERO, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glUseProgram(ppass->prog); - //bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); + + // If caller specified a texture use it as source if (ptex) { - log_warn("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); - bind_sampler_to_unit_with_texture(ppass->prog, "tex_bg", 0, ptex->target, ptex->texture); + log_debug("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); + bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, ptex->target, ptex->texture); + } else { + bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); } if (ppass->unifm_radius >= 0) @@ -1306,29 +1292,7 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); // Painting - /*if (shader_idx == 1) { - P_PAINTREG_START(crect) { - // XXX what does all of these variables mean? - auto rdx = (GLfloat)crect.x1; - auto rdy = (GLfloat)(ps->root_height - crect.y1); - auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1); - -#ifdef DEBUG_GLX - log_debug("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); -#endif - - log_warn("Rounded corner Pass: %d, %d, %.2f -> %f, %f, %f, %f", - crect.x1, crect.y1, z, rdx, rdy, rdxe, rdye); - - glVertex3f(rdx, rdy, z); - glVertex3f(rdxe, rdy, z); - glVertex3f(rdxe, rdye,z); - glVertex3f(rdx, rdye, z); - } - P_PAINTREG_END(); - - } else*/ { + { P_PAINTREG_START(crect) { // XXX explain these variables auto rx = (GLfloat)(crect.x1 - dx); @@ -1356,12 +1320,8 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused rye = 1.0f - rye; } - log_warn("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", - ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); - - // log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, - // ry, rxe, rye, - // rdx, rdy, rdxe, rdye); + //log_trace("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", + // ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); glTexCoord2f(rx, ry); glVertex3f(rdx, rdy, z); @@ -1412,14 +1372,12 @@ bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader assert(ps->psglx->round_passes[1].prog); bool ret = false; - log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) z(%.2f)", dx, dy, width, height, ps->root_width, ps->root_height, z); - { const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; assert(ppass->prog); glEnable(GL_BLEND); - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(ppass->prog); @@ -1461,12 +1419,8 @@ bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader rye = 1.0f - rye; } - log_warn("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", - ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); - - // log_trace("Rect %d: %f, %f, %f, %f -> %d, %d, %d, %d", ri, rx, - // ry, rxe, rye, - // rdx, rdy, rdxe, rdye); + //log_trace("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", + // ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); glTexCoord2f(rx, ry); glVertex3f(rdx, rdy, z); @@ -1540,7 +1494,6 @@ bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_text const bool has_prog = pprogram && pprogram->prog; bool dual_texture = false; - GLuint tex_scr = ptex->texture; // It's required by legacy versions of OpenGL to enable texture target // before specifying environment. Thanks to madsy for telling me. @@ -1594,7 +1547,7 @@ bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_text // Texture stage 1 glActiveTexture(GL_TEXTURE1); glEnable(ptex->target); - glBindTexture(ptex->target, tex_scr); + glBindTexture(ptex->target, ptex->texture); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); @@ -1650,10 +1603,10 @@ bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_text // dx, dy, ptex->width, ptex->height, z); // Bind texture - glBindTexture(ptex->target, tex_scr); + glBindTexture(ptex->target, ptex->texture); if (dual_texture) { glActiveTexture(GL_TEXTURE1); - glBindTexture(ptex->target, tex_scr); + glBindTexture(ptex->target, ptex->texture); glActiveTexture(GL_TEXTURE0); } @@ -1680,7 +1633,7 @@ bool glx_render(session_t *ps, struct managed_win *w attr_unused, const glx_text // Invert Y if needed, this may not work as expected, though. I // don't have such a FBConfig to test with. - if (!ptex->y_inverted || tex_scr != ptex->texture) { + if (!ptex->y_inverted) { ry = 1.0f - ry; rye = 1.0f - rye; } diff --git a/src/opengl.h b/src/opengl.h index 7c9169d813..40a63a9208 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -112,7 +112,7 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex); bool glx_bind_texture(session_t *ps, glx_texture_t **pptex, int x, int y, int width, int height, bool repeat); -void glx_release_texture(session_t *ps attr_unused, glx_texture_t **ptex); +void glx_release_texture(session_t *ps, glx_texture_t **ptex); void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2); diff --git a/src/render.c b/src/render.c index 0e1e5a10f7..b82522e025 100644 --- a/src/render.c +++ b/src/render.c @@ -369,7 +369,7 @@ win_round_corners(session_t *ps, struct managed_win *w, const glx_texture_t *pte const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); - log_warn("x:%d y:%d w:%d h:%d", x, y, wid, hei); + //log_debug("x:%d y:%d w:%d h:%d", x, y, wid, hei); switch (ps->o.backend) { case BKEND_XRENDER: @@ -1088,8 +1088,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Round window corners if (w->corner_radius > 0) { - win_round_corners(ps, w, w->glx_texture_bg, - 0, (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } + win_round_corners(ps, w, w->glx_texture_bg, 0, + (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } } } From 7aa5f0d7ebf40b0ba41eee330681a5c5b7907fdb Mon Sep 17 00:00:00 2001 From: bhagwan Date: Wed, 1 Apr 2020 10:05:37 -0700 Subject: [PATCH 25/38] init rounded corners shader only if glx backend is used --- src/render.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index b82522e025..48a1164144 100644 --- a/src/render.c +++ b/src/render.c @@ -1345,11 +1345,15 @@ bool init_render(session_t *ps) { } // Initialize our rounded corners fragment shader - if (ps->o.corner_radius > 0) { + if (ps->o.corner_radius > 0 && ps->o.backend == BKEND_GLX) { +#ifdef CONFIG_OPENGL if (!glx_init_rounded_corners(ps)) { log_error("Failed to init rounded corners shader."); return false; } +#else + assert(false); +#endif } return true; } From 510cd993e9211a073be288c97d57728d5027c1af Mon Sep 17 00:00:00 2001 From: bhagwan Date: Wed, 1 Apr 2020 19:18:00 -0700 Subject: [PATCH 26/38] rewrote shader code for better rounded corner rendering --- src/opengl.c | 121 ++++++++++++++++++++++++++++++++++++++++++++------- src/opengl.h | 8 +++- src/render.c | 4 +- 3 files changed, 113 insertions(+), 20 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 5e5f0df538..4276c83f70 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -105,6 +105,7 @@ bool glx_init(session_t *ps, bool need_render) { ppass->unifm_radius = -1; ppass->unifm_texcoord = -1; ppass->unifm_texsize = -1; + ppass->unifm_borderw = -1; ppass->unifm_resolution = -1; } } @@ -488,6 +489,8 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, P_GET_UNIFM_LOC("u_radius", unifm_radius); P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); P_GET_UNIFM_LOC("u_texsize", unifm_texsize); + P_GET_UNIFM_LOC("u_borderw", unifm_borderw); + P_GET_UNIFM_LOC("u_is_focused", unifm_is_focused); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); #undef P_GET_UNIFM_LOC } @@ -510,11 +513,18 @@ bool glx_init_rounded_corners(session_t *ps) { "#version 110\n" "%s" // extensions "uniform float u_radius;\n" + "uniform float u_borderw;\n" + "uniform int u_is_focused;\n" "uniform vec2 u_texcoord;\n" "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect "\n" + "// https://www.shadertoy.com/view/ltS3zW\n" + "float RectSDF(vec2 p, vec2 b, float r) {\n" + " vec2 d = abs(p) - b + vec2(r);\n" + " return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;\n" + "}\n\n" "// https://www.shadertoy.com/view/ldfSDj\n" "float udRoundBox( vec2 p, vec2 b, float r )\n" "{\n" @@ -522,32 +532,96 @@ bool glx_init_rounded_corners(session_t *ps) { "}\n\n" "void main()\n" "{\n" - " vec4 col_scr = %s(tex_scr, gl_TexCoord[0].st);\n" - " vec2 halfres = 0.5 * u_texsize.xy;\n" " vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);\n" - "\n" - " // compute box\n" - " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres, u_radius );\n" + " vec4 u_v4SrcColor = %s(tex_scr, vec2(gl_TexCoord[0].st));\n" "\n"; // Fragment shader (round corners) // dst0 shader - static const char *FRAG_SHADER_ROUND_CORNERS_PRE = + static const char *FRAG_SHADER_ROUND_CORNERS_0 = + " float u_fRadiusPx = u_radius;\n" + " float u_fHalfBorderThickness = 0.0;\n" + " vec4 u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + " vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0);\n" + " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" + " vec4 v4ToColor = u_v4SrcColor; //Outside color is the background texture\n" + "\n" + " //if (u_is_focused > 0) u_fHalfBorderThickness = u_borderw / 2.0;\n" + " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" + " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" + "\n" + " float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_fRadiusPx - u_fHalfBorderThickness);\n" + " if (u_fHalfBorderThickness > 0.0) {\n" + " if (fDist < 0.0) {\n" + " v4ToColor = u_v4FillColor;\n" + " }\n" + " fDist = abs(fDist) - u_fHalfBorderThickness;\n" + " } else {\n" + " v4FromColor = u_v4FillColor;\n" + " }\n" + " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" + " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" + "\n" + " // final color\n" + " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" + " gl_FragColor = c;\n" + "\n" + " // OLD SHADER" + " // compute box\n" + " /*vec2 halfres = 0.5 * vec2(u_texsize.x - 0.0, u_texsize.y - 0.0);\n" + " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres - 0.0, u_radius + 0.0 );\n" + "\n" " // colorize (transparent mid / opaque corners )\n" - " vec4 c = mix( vec4(0.0,0.0,0.0,0.0), col_scr, smoothstep(0.0,1.0,b) );\n" + " c = mix( vec4(0.0,0.0,0.0,0.0), u_v4SrcColor, smoothstep(0.0,1.0,b) );\n" "\n" " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" - " gl_FragColor = vec4( c );\n" + " gl_FragColor = vec4( c );*/\n" "}\n"; // Fragment shader (round corners) // dst1 shader - static const char *FRAG_SHADER_ROUND_CORNERS_POST = + static const char *FRAG_SHADER_ROUND_CORNERS_1 = + " float u_fRadiusPx = u_radius;\n" + " float u_fHalfBorderThickness = 10.0 /2.0;//0.0;\n" + " vec4 u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + " vec4 u_v4FillColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + " //vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0);\n" + " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" + " vec4 v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color\n" + " //vec4 v4ToColor = u_v4SrcColor; //Outside color\n" + "\n" + " if (u_is_focused > 0) u_fHalfBorderThickness = u_borderw / 2.0 * 4.02;\n" + " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" + " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" + "\n" + " float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_fRadiusPx - u_fHalfBorderThickness);\n" + " if (u_fHalfBorderThickness > 0.0) {\n" + " if (fDist < 0.0) {\n" + " v4ToColor = u_v4FillColor;\n" + " }\n" + " fDist = abs(fDist) - u_fHalfBorderThickness;\n" + " } else {\n" + " v4FromColor = u_v4FillColor;\n" + " }\n" + " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" + " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" + "\n" + " // final color\n" + " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" + " gl_FragColor = c;\n" + " //gl_FragColor = vec4(vec3(fBlendAmount), 1.0);\n" + " //gl_FragColor = vec4(vec3(abs(dist) / (2.0 * corner)), 1.0);\n" + "\n\n" + " // OLD SHADER" + " // compute box\n" + " /*vec2 halfres = 0.5 * vec2(u_texsize.x - 0.0, u_texsize.y - 0.0);\n" + " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres - 0.0, u_radius + 0.0 );\n" + "\n" " // colorize (red / green )\n" - " vec4 c = mix( vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,0.0,1.0), smoothstep(0.0,1.0,b) );\n" + " c = mix( vec4(0.0,1.0,0.0,1.0), vec4(0.0,0.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" "\n" " //if ( c == vec4(1.0,1.0,1.0,1.0) ) discard; else\n" - " gl_FragColor = vec4( c );\n" + " gl_FragColor = vec4( c );*/\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -563,7 +637,7 @@ bool glx_init_rounded_corners(session_t *ps) { } if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[0], - FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_PRE, + FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_0, extension, sampler_type, texture_func)) { log_error("Failed to create rounded corners fragment shader PRE."); @@ -574,7 +648,7 @@ bool glx_init_rounded_corners(session_t *ps) { } if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[1], - FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_POST, + FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_1, extension, sampler_type, texture_func)) { log_error("Failed to create rounded corners fragment shader POST."); @@ -1187,7 +1261,7 @@ static void bind_sampler_to_unit_with_texture(GLuint prog, GLchar const * const } -bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused, int shader_idx, +bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex attr_unused, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { @@ -1198,7 +1272,8 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; - //log_trace("dxy(%d, %d) wh(%d %d) rwh(%d %d)", dx, dy, width, height, ps->root_width, ps->root_height); + //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) b(%d), f(%d)", + // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width, w->focused); // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; @@ -1288,6 +1363,10 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); if (ppass->unifm_texsize >= 0) glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); + if (ppass->unifm_borderw >= 0) + glUniform1f(ppass->unifm_borderw, w->g.border_width); + if (ppass->unifm_is_focused >= 0) + glUniform1i(ppass->unifm_is_focused, w->focused); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); @@ -1363,7 +1442,7 @@ bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex attr_unused return ret; } -bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { @@ -1381,12 +1460,22 @@ bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader glUseProgram(ppass->prog); + // If caller specified a texture use it as source + if (ptex) { + log_debug("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); + bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, ptex->target, ptex->texture); + } + if (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); if (ppass->unifm_texcoord >= 0) glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); if (ppass->unifm_texsize >= 0) glUniform2f(ppass->unifm_texsize, (float)width, (float)height); + if (ppass->unifm_borderw >= 0) + glUniform1f(ppass->unifm_borderw, w->g.border_width); + if (ppass->unifm_is_focused >= 0) + glUniform1i(ppass->unifm_is_focused, w->focused); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); diff --git a/src/opengl.h b/src/opengl.h index 40a63a9208..70d0992742 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -51,6 +51,10 @@ typedef struct { GLint unifm_texcoord; /// Location of uniform "texsize" in rounded-corners GLSL program. GLint unifm_texsize; + /// Location of uniform "borderw" in rounded-corners GLSL program. + GLint unifm_borderw; + /// Location of uniform "is_focused" in rounded-corners GLSL program. + GLint unifm_is_focused; /// Location of uniform "resolution" in rounded-corners GLSL program. GLint unifm_resolution; } glx_round_pass_t; @@ -128,11 +132,11 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst0(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst1(session_t *ps, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc); diff --git a/src/render.c b/src/render.c index 48a1164144..f8daee3c43 100644 --- a/src/render.c +++ b/src/render.c @@ -379,10 +379,10 @@ win_round_corners(session_t *ps, struct managed_win *w, const glx_texture_t *pte #ifdef CONFIG_OPENGL case BKEND_GLX: if (shader_idx == 1) { - glx_round_corners_dst1(ps, ptex, shader_idx, x, y, wid, hei, + glx_round_corners_dst1(ps, w, ptex, shader_idx, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); } else { - glx_round_corners_dst0(ps, ptex, shader_idx, x, y, wid, hei, + glx_round_corners_dst0(ps, w, ptex, shader_idx, x, y, wid, hei, (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); } break; From 27486e441ecba7f2cb7dc2ced1ea7f661b203819 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Wed, 1 Apr 2020 22:56:42 -0700 Subject: [PATCH 27/38] wip: rounded borders almost working, need to add source alpha to pixel --- src/opengl.c | 43 ++++++++++++++++++++++++++++++++----------- src/opengl.h | 4 ++-- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 4276c83f70..f83dbe4d62 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -106,6 +106,7 @@ bool glx_init(session_t *ps, bool need_render) { ppass->unifm_texcoord = -1; ppass->unifm_texsize = -1; ppass->unifm_borderw = -1; + ppass->unifm_borderc = -1; ppass->unifm_resolution = -1; } } @@ -490,7 +491,7 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, P_GET_UNIFM_LOC("u_texcoord", unifm_texcoord); P_GET_UNIFM_LOC("u_texsize", unifm_texsize); P_GET_UNIFM_LOC("u_borderw", unifm_borderw); - P_GET_UNIFM_LOC("u_is_focused", unifm_is_focused); + P_GET_UNIFM_LOC("u_borderc", unifm_borderc); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); #undef P_GET_UNIFM_LOC } @@ -514,7 +515,7 @@ bool glx_init_rounded_corners(session_t *ps) { "%s" // extensions "uniform float u_radius;\n" "uniform float u_borderw;\n" - "uniform int u_is_focused;\n" + "uniform vec4 u_borderc;\n" "uniform vec2 u_texcoord;\n" "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" @@ -546,7 +547,10 @@ bool glx_init_rounded_corners(session_t *ps) { " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" " vec4 v4ToColor = u_v4SrcColor; //Outside color is the background texture\n" "\n" - " //if (u_is_focused > 0) u_fHalfBorderThickness = u_borderw / 2.0;\n" + " /*if (u_borderw > 0.) {\n" + " v4FromColor = u_borderc;\n" + " u_fHalfBorderThickness = u_borderw / 2.0;\n" + " }*/\n" " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" "\n" @@ -590,7 +594,10 @@ bool glx_init_rounded_corners(session_t *ps) { " vec4 v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color\n" " //vec4 v4ToColor = u_v4SrcColor; //Outside color\n" "\n" - " if (u_is_focused > 0) u_fHalfBorderThickness = u_borderw / 2.0 * 4.02;\n" + " /*if (u_borderw > 0.0f) {\n" + " v4FromColor = u_borderc;\n" + " u_fHalfBorderThickness = u_borderw / 2.0;\n" + " }*/\n" " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" "\n" @@ -735,7 +742,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, // Release texture if parameters are inconsistent if (ptex && ptex->texture && (ptex->width != width || ptex->height != height)) { - log_info("Windows size changed old_wh(%d %d) new_wh(%d %d)", ptex->width, ptex->height, width, height); + //log_info("Windows size changed old_wh(%d %d) new_wh(%d %d)", ptex->width, ptex->height, width, height); glx_release_texture(ps, &ptex); } @@ -1271,9 +1278,17 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; + + GLfloat border_col[4] = {0}; + + if (w->g.border_width >= 1) { + glReadPixels(dx, dy+height, 1, 1, GL_RGBA, GL_FLOAT, (void*)&border_col[0]); + //log_warn("border_col(%.2f, %.2f, %.2f, %.2f)", + // (float)border_col[0], (float)border_col[1], (float)border_col[2], (float)border_col[3]); + } - //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) b(%d), f(%d)", - // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width, w->focused); + //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) bw(%d)", + // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width); // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; @@ -1365,8 +1380,8 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); if (ppass->unifm_borderw >= 0) glUniform1f(ppass->unifm_borderw, w->g.border_width); - if (ppass->unifm_is_focused >= 0) - glUniform1i(ppass->unifm_is_focused, w->focused); + if (ppass->unifm_borderc >= 0) + glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&border_col[0]); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); @@ -1451,6 +1466,12 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text assert(ps->psglx->round_passes[1].prog); bool ret = false; + GLfloat border_col[4] = {0}; + + if (w->g.border_width >= 1) { + glReadPixels(dx, dy+height, 1, 1, GL_RGBA, GL_FLOAT, (void*)&border_col[0]); + } + { const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; assert(ppass->prog); @@ -1474,8 +1495,8 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text glUniform2f(ppass->unifm_texsize, (float)width, (float)height); if (ppass->unifm_borderw >= 0) glUniform1f(ppass->unifm_borderw, w->g.border_width); - if (ppass->unifm_is_focused >= 0) - glUniform1i(ppass->unifm_is_focused, w->focused); + if (ppass->unifm_borderc >= 0) + glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&border_col[0]); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); diff --git a/src/opengl.h b/src/opengl.h index 70d0992742..434505f349 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -53,8 +53,8 @@ typedef struct { GLint unifm_texsize; /// Location of uniform "borderw" in rounded-corners GLSL program. GLint unifm_borderw; - /// Location of uniform "is_focused" in rounded-corners GLSL program. - GLint unifm_is_focused; + /// Location of uniform "borderc" in rounded-corners GLSL program. + GLint unifm_borderc; /// Location of uniform "resolution" in rounded-corners GLSL program. GLint unifm_resolution; } glx_round_pass_t; From e4392afe384511b76061e5793060364dccd12b34 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Thu, 2 Apr 2020 12:29:23 -0700 Subject: [PATCH 28/38] wip: removed old shader, rounded borders almost perfect --- src/opengl.c | 140 ++++++++++++++++++++++----------------------------- src/opengl.h | 5 ++ src/render.c | 2 +- 3 files changed, 65 insertions(+), 82 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index f83dbe4d62..a915fab561 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -108,6 +108,8 @@ bool glx_init(session_t *ps, bool need_render) { ppass->unifm_borderw = -1; ppass->unifm_borderc = -1; ppass->unifm_resolution = -1; + ppass->unifm_tex_scr = -1; + ppass->unifm_tex_wnd = -1; } } @@ -437,13 +439,13 @@ bool glx_init_blur(session_t *ps) { } static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, - const char *PREFIX_STR, const char* SHADER_STR, + const int shader_idx, const char *PREFIX_STR, const char* SHADER_STR, const char *extension, const char *sampler_type, const char *texture_func) { // Build rounded corners shader { auto len = strlen(PREFIX_STR) + strlen(extension) - + strlen(sampler_type) + strlen(texture_func) + + strlen(sampler_type)*2 + strlen(texture_func)*2 + strlen(SHADER_STR) + 1; char *shader_str = calloc(len, sizeof(char)); if (!shader_str) { @@ -452,16 +454,18 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, } char *pc = shader_str; - sprintf(pc, PREFIX_STR, extension, sampler_type, texture_func); + sprintf(pc, PREFIX_STR, extension, sampler_type, sampler_type, texture_func, texture_func); pc += strlen(pc); assert(strlen(shader_str) < len); sprintf(pc, SHADER_STR); assert(strlen(shader_str) < len); #ifdef DEBUG_GLX - log_debug("Generated rounded corners shader:\n%s\n", shader_str); + log_debug("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); #endif + log_info("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); + ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); free(shader_str); @@ -483,8 +487,8 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, ppass->target = glGetUniformLocation(ppass->prog, name); \ if (ppass->target < 0) { \ log_error("Failed to get location of rounded corners uniform '" name \ - "'. Might be troublesome." \ - ); \ + "'. Might be troublesome. (shader_idx: %d)" \ + , shader_idx); \ } \ } P_GET_UNIFM_LOC("u_radius", unifm_radius); @@ -493,6 +497,8 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, P_GET_UNIFM_LOC("u_borderw", unifm_borderw); P_GET_UNIFM_LOC("u_borderc", unifm_borderc); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); + P_GET_UNIFM_LOC("tex_scr", unifm_tex_scr); + P_GET_UNIFM_LOC("tex_wnd", unifm_tex_wnd); #undef P_GET_UNIFM_LOC } @@ -520,37 +526,34 @@ bool glx_init_rounded_corners(session_t *ps) { "uniform vec2 u_texsize;\n" "uniform vec2 u_resolution;\n" "uniform %s tex_scr;\n" // sampler2D | sampler2DRect + "uniform %s tex_wnd;\n" // sampler2D | sampler2DRect "\n" "// https://www.shadertoy.com/view/ltS3zW\n" "float RectSDF(vec2 p, vec2 b, float r) {\n" " vec2 d = abs(p) - b + vec2(r);\n" " return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;\n" - "}\n\n" - "// https://www.shadertoy.com/view/ldfSDj\n" - "float udRoundBox( vec2 p, vec2 b, float r )\n" - "{\n" - " return length(max(abs(p)-b+r,0.0))-r;\n" "}\n\n" "void main()\n" "{\n" " vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y);\n" - " vec4 u_v4SrcColor = %s(tex_scr, vec2(gl_TexCoord[0].st));\n" + " // Get the window_bg color (so we can \"erase\" corners) from the bg texture\n" + " // and the border color from the mid x-axis of the target window (hacky...)\n" + " vec4 u_v4WndBgColor = %s(tex_scr, vec2(gl_TexCoord[0].st));\n" + " vec4 u_v4BorderColor = %s(tex_wnd, vec2(0, u_texsize.t/2.));\n" + " vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect, transparent\n" + " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" + " vec4 v4ToColor = u_v4WndBgColor; //Outside corners color, we set it to background texture\n" "\n"; // Fragment shader (round corners) // dst0 shader static const char *FRAG_SHADER_ROUND_CORNERS_0 = " float u_fRadiusPx = u_radius;\n" - " float u_fHalfBorderThickness = 0.0;\n" - " vec4 u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" - " vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0);\n" - " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" - " vec4 v4ToColor = u_v4SrcColor; //Outside color is the background texture\n" + " float u_fHalfBorderThickness = u_borderw / 2.0;\n" + " //v4FromColor = u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + " //u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect color\n" + "\n" - " /*if (u_borderw > 0.) {\n" - " v4FromColor = u_borderc;\n" - " u_fHalfBorderThickness = u_borderw / 2.0;\n" - " }*/\n" " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" "\n" @@ -569,35 +572,17 @@ bool glx_init_rounded_corners(session_t *ps) { " // final color\n" " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " gl_FragColor = c;\n" - "\n" - " // OLD SHADER" - " // compute box\n" - " /*vec2 halfres = 0.5 * vec2(u_texsize.x - 0.0, u_texsize.y - 0.0);\n" - " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres - 0.0, u_radius + 0.0 );\n" - "\n" - " // colorize (transparent mid / opaque corners )\n" - " c = mix( vec4(0.0,0.0,0.0,0.0), u_v4SrcColor, smoothstep(0.0,1.0,b) );\n" - "\n" - " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" - " gl_FragColor = vec4( c );*/\n" "}\n"; // Fragment shader (round corners) // dst1 shader static const char *FRAG_SHADER_ROUND_CORNERS_1 = - " float u_fRadiusPx = u_radius;\n" - " float u_fHalfBorderThickness = 10.0 /2.0;//0.0;\n" - " vec4 u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" - " vec4 u_v4FillColor = vec4(0.0, 1.0, 0.0, 1.0);\n" - " //vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0);\n" - " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" - " vec4 v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color\n" - " //vec4 v4ToColor = u_v4SrcColor; //Outside color\n" + " float u_fRadiusPx = u_radius + 25.0;\n" + " float u_fHalfBorderThickness = 20.0 /2.0;\n" + " //u_v4FillColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + " //v4FromColor = u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + " //v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color\n" "\n" - " /*if (u_borderw > 0.0f) {\n" - " v4FromColor = u_borderc;\n" - " u_fHalfBorderThickness = u_borderw / 2.0;\n" - " }*/\n" " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" "\n" @@ -618,17 +603,6 @@ bool glx_init_rounded_corners(session_t *ps) { " gl_FragColor = c;\n" " //gl_FragColor = vec4(vec3(fBlendAmount), 1.0);\n" " //gl_FragColor = vec4(vec3(abs(dist) / (2.0 * corner)), 1.0);\n" - "\n\n" - " // OLD SHADER" - " // compute box\n" - " /*vec2 halfres = 0.5 * vec2(u_texsize.x - 0.0, u_texsize.y - 0.0);\n" - " float b = udRoundBox( gl_FragCoord.xy - coord - halfres, halfres - 0.0, u_radius + 0.0 );\n" - "\n" - " // colorize (red / green )\n" - " c = mix( vec4(0.0,1.0,0.0,1.0), vec4(0.0,0.0,1.0,1.0), smoothstep(0.0,1.0,b) );\n" - "\n" - " //if ( c == vec4(1.0,1.0,1.0,1.0) ) discard; else\n" - " gl_FragColor = vec4( c );*/\n" "}\n"; const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two; @@ -643,7 +617,7 @@ bool glx_init_rounded_corners(session_t *ps) { extension = strdup(""); } - if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[0], + if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[0], 0, FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_0, extension, sampler_type, texture_func)) { @@ -654,7 +628,7 @@ bool glx_init_rounded_corners(session_t *ps) { return false; } - if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[1], + if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[1], 1, FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_1, extension, sampler_type, texture_func)) { @@ -1259,15 +1233,6 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, } -static void bind_sampler_to_unit_with_texture(GLuint prog, GLchar const * const sampler_name, GLuint texture_unit, GLenum tex_tgt, GLuint texture) -{ - glActiveTexture(GL_TEXTURE0 + texture_unit); - glBindTexture(tex_tgt, texture); - GLint loc_sampler = glGetUniformLocation(prog, sampler_name); - glUniform1i(loc_sampler, (GLint)texture_unit); -} - - bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex attr_unused, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { @@ -1342,8 +1307,19 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text assert(ppass->prog); assert(tex_scr); + + glActiveTexture(GL_TEXTURE1); glBindTexture(tex_tgt, tex_scr); + // If caller specified a texture use it as source + if (ptex) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(ptex->target, ptex->texture); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(tex_tgt, tex_scr); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); glDrawBuffer(GL_BACK); if (have_scissors) @@ -1363,14 +1339,10 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text glUseProgram(ppass->prog); - - // If caller specified a texture use it as source - if (ptex) { - log_debug("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); - bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, ptex->target, ptex->texture); - } else { - bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, tex_tgt, tex_scr); - } + if (ppass->unifm_tex_scr >= 0) + glUniform1i(ppass->unifm_tex_scr, (GLint)0); + if (ppass->unifm_tex_wnd >= 0) + glUniform1i(ppass->unifm_tex_wnd, (GLint)1); if (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); @@ -1409,7 +1381,7 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text // Invert Y if needed, this may not work as expected, though. I // don't have such a FBConfig to test with. //if (ptex && !ptex->y_inverted) { - if (shader_idx == 0) { + { ry = 1.0f - ry; rye = 1.0f - rye; } @@ -1476,16 +1448,22 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; assert(ppass->prog); + // If caller specified a texture use it as source + if (ptex) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(ptex->target, ptex->texture); + } + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(ppass->prog); - // If caller specified a texture use it as source - if (ptex) { - log_debug("ptex: %p wh(%d %d) %d %d", ptex, ptex->width, ptex->height, ptex->target, ptex->texture); - bind_sampler_to_unit_with_texture(ppass->prog, "tex_scr", 0, ptex->target, ptex->texture); - } + if (ppass->unifm_tex_scr >= 0) + glUniform1i(ppass->unifm_tex_scr, (GLint)0); + // We have no GL_TEXTURE1 here so just pass the default + if (ppass->unifm_tex_wnd >= 0) + glUniform1i(ppass->unifm_tex_wnd, (GLint)0); if (ppass->unifm_radius >= 0) glUniform1f(ppass->unifm_radius, cr); @@ -1524,7 +1502,7 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text // Invert Y if needed, this may not work as expected, though. I // don't have such a FBConfig to test with. //if (ptex && !ptex->y_inverted) { - if (shader_idx == 0) { + { ry = 1.0f - ry; rye = 1.0f - rye; } diff --git a/src/opengl.h b/src/opengl.h index 434505f349..8475bc6672 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -57,6 +57,11 @@ typedef struct { GLint unifm_borderc; /// Location of uniform "resolution" in rounded-corners GLSL program. GLint unifm_resolution; + /// Location of uniform "texture_scr" in rounded-corners GLSL program. + GLint unifm_tex_scr; + /// Location of uniform "texture_wnd" in rounded-corners GLSL program. + GLint unifm_tex_wnd; + } glx_round_pass_t; /// Structure containing GLX-dependent data for a session. diff --git a/src/render.c b/src/render.c index f8daee3c43..62fa641268 100644 --- a/src/render.c +++ b/src/render.c @@ -1089,7 +1089,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Round window corners if (w->corner_radius > 0) { win_round_corners(ps, w, w->glx_texture_bg, 0, - (float)w->corner_radius, ps->tgt_buffer.pict, &bshape_corners); } + (float)w->corner_radius, ps->tgt_buffer.pict, ®_tmp); } } } From 2d13d16a6a203aaa463e7e115bc462a9cab8a0b6 Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 3 Apr 2020 04:07:07 +0100 Subject: [PATCH 29/38] Smooth glx corners --- src/opengl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index a915fab561..117492f4b5 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -566,8 +566,9 @@ bool glx_init_rounded_corners(session_t *ps) { " } else {\n" " v4FromColor = u_v4FillColor;\n" " }\n" - " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" - " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" + " float fBlendAmount = clamp(fDist + 0.5, 0, 1);\n" + " //vec4 c = fDist <= 0.0 ? v4FromColor : v4ToColor;\n" + " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);\n" "\n" " // final color\n" " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" @@ -595,7 +596,7 @@ bool glx_init_rounded_corners(session_t *ps) { " } else {\n" " v4FromColor = u_v4FillColor;\n" " }\n" - " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" + " float fBlendAmount = clamp(fDist + 0.5, 0, 1);\n" " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" "\n" " // final color\n" From c732c9fdcd9789538dd5b9aef370fc546365379a Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Fri, 3 Apr 2020 20:10:05 +0100 Subject: [PATCH 30/38] Fix memory leak? --- src/backend/xrender/xrender.c | 1 + src/event.c | 1 + src/win.h | 1 + 3 files changed, 3 insertions(+) diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index ee35e216a7..db540ae985 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -286,6 +286,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, xcb_render_free_picture(c, tmp_picture[0]); xcb_render_free_picture(c, tmp_picture[1]); pixman_region32_fini(®_op); + pixman_region32_fini(®_op_resized); return true; } diff --git a/src/event.c b/src/event.c index 4a0333848b..0f5571b7b6 100644 --- a/src/event.c +++ b/src/event.c @@ -372,6 +372,7 @@ static inline void expose_root(session_t *ps, const rect_t *rects, int nrects) { region_t region; pixman_region32_init_rects(®ion, rects, nrects); add_damage(ps, ®ion); + pixman_region32_fini(®ion); } static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) { diff --git a/src/win.h b/src/win.h index 82b1df00cd..596c050cde 100644 --- a/src/win.h +++ b/src/win.h @@ -454,6 +454,7 @@ static inline void win_region_remove_corners(const struct managed_win *w, region }, 4); pixman_region32_subtract(res, res, &corners); + pixman_region32_fini(&corners); } static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w, bool include_corners) { From e370ec2c0b5907020ca2cb9bde00f7d511c9d8cf Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Sat, 4 Apr 2020 01:18:29 +0100 Subject: [PATCH 31/38] Don't render shadows behind rounded corner windows with the xrender backend --- src/render.c | 44 +++++++++++++++++++++++++++++++++++++++----- src/render.h | 9 ++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/render.c b/src/render.c index 62fa641268..3c58852cbc 100644 --- a/src/render.c +++ b/src/render.c @@ -247,7 +247,7 @@ uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ void render(session_t *ps, struct managed_win *w, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, - const region_t *reg_paint, const glx_prog_main_t *pprogram) { + const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip) { switch (ps->o.backend) { case BKEND_XRENDER: case BKEND_XR_GLX_HYBRID: { @@ -286,14 +286,30 @@ void render(session_t *ps, struct managed_win *w, int x, int y, int dx, int dy, xcb_render_free_picture(ps->c, p_tmp); } else { + xcb_render_picture_t p_tmp = alpha_pict; + if(clip){ + p_tmp = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + + xcb_render_color_t black = {.red = 255, .blue = 255, .green = 255, .alpha = 255}; + const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)}; + xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, p_tmp, black, 1, &rect); + if(alpha_pict) { + xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, 0, 0, 0, to_u16_checked(wid), to_u16_checked(hei)); + } + xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE, clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, to_i16_checked(clip->x), to_i16_checked(clip->y), to_u16_checked(wid), to_u16_checked(hei)); + } uint8_t op = - ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC + ((!argb && !alpha_pict && !clip) ? XCB_RENDER_PICT_OP_SRC : XCB_RENDER_PICT_OP_OVER); + xcb_render_composite( - ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict, + ps->c, op, pict, p_tmp, ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx), to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); + if(clip){ + xcb_render_free_picture(ps->c, p_tmp); + } } } break; @@ -333,7 +349,7 @@ paint_region(session_t *ps, struct managed_win *w, int x, int y, int wid, int he #else NULL #endif - ); + , XCB_NONE); } /** @@ -747,9 +763,27 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { return; } + xcb_render_picture_t td = XCB_NONE; + if (w->corner_radius) { + uint32_t max_ntraps = to_u32_checked(w->corner_radius); + xcb_render_trapezoid_t traps[4 * max_ntraps + 5]; + uint32_t n = make_rounded_window_shape(traps, max_ntraps, w->corner_radius, w->widthb, w->heightb); + + td = x_create_picture_with_standard(ps->c, ps->root, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0); + xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0}; + const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(w->widthb), .height = to_u16_checked(w->heightb)}; + xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); + + xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + } + + clip_t clip = { .pict = td, -(w->shadow_dx), .y = -(w->shadow_dy) }; render(ps, w, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, w->shadow_paint.pict, - w->shadow_paint.ptex, reg_paint, NULL); + w->shadow_paint.ptex, reg_paint, NULL, w->corner_radius ? &clip : NULL); + if(td){ + xcb_render_free_picture(ps->c, td); + } } /** diff --git a/src/render.h b/src/render.h index ced66d40dd..335a020bdd 100644 --- a/src/render.h +++ b/src/render.h @@ -25,9 +25,16 @@ typedef struct paint { #endif } paint_t; + +typedef struct clip { + xcb_render_picture_t pict; + int x; + int y; +} clip_t; + void render(session_t *ps, struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, - const region_t *reg_paint, const glx_prog_main_t *pprogram); + const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip); void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); void paint_all(session_t *ps, struct managed_win *const t, bool ignore_damage); From 32d667813b3422e30490c0e4e734df38e9732f5d Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Sat, 4 Apr 2020 02:42:24 +0100 Subject: [PATCH 32/38] Fix frame opacity --- src/win.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/win.c b/src/win.c index ff271a9851..7bd385e35a 100644 --- a/src/win.c +++ b/src/win.c @@ -565,9 +565,6 @@ winmode_t win_calc_mode(session_t *ps, const struct managed_win *w) { if (w->opacity < 1.0) { return WMODE_TRANS; } - if (w->frame_opacity != 1.0 && win_has_frame(w)) { - return WMODE_FRAME_TRANS; - } if (ps->o.backend == BKEND_GLX && w->corner_radius > 0) { return WMODE_TRANS; @@ -594,6 +591,10 @@ winmode_t win_calc_mode(session_t *ps, const struct managed_win *w) { // consider the window solid } + if (w->frame_opacity != 1.0 && win_has_frame(w)) { + return WMODE_FRAME_TRANS; + } + // log_trace("Window %#010x(%s) is solid", w->client_win, w->name); return WMODE_SOLID; } From e1b55709c2c0e8bb54546c700aac3ef446c465db Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Sat, 4 Apr 2020 03:53:22 +0100 Subject: [PATCH 33/38] Fix (another) memory leak --- src/render.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/render.c b/src/render.c index 3c58852cbc..8fe6e87de7 100644 --- a/src/render.c +++ b/src/render.c @@ -774,7 +774,9 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(w->widthb), .height = to_u16_checked(w->heightb)}; xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); - xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); + xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + xcb_render_free_picture(ps->c, solid); } clip_t clip = { .pict = td, -(w->shadow_dx), .y = -(w->shadow_dy) }; @@ -909,7 +911,10 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)}; xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); - xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); + + xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); + xcb_render_free_picture(ps->c, solid); } // Minimize the region we try to blur, if the window itself is not @@ -928,6 +933,9 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t pixman_region32_translate(®_blur, -x, -y); xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, ps->o.blur_kernel_count, ®_blur, td); + if(td){ + xcb_render_free_picture(ps->c, td); + } pixman_region32_clear(®_blur); } break; #ifdef CONFIG_OPENGL From bae5bf01ce4b58da0c2e6f0ab57ae6142be8da84 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Fri, 3 Apr 2020 18:13:37 -0700 Subject: [PATCH 34/38] rounded borders working with one-colored borders --- src/opengl.c | 67 ++++++++++++++++++++++++++++++++++++---------------- src/picom.c | 4 ++++ src/win.c | 24 +++++++++++++++++++ src/win.h | 1 + 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index e0d2636d22..2f7e185105 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -461,7 +461,7 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, log_debug("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); #endif - log_info("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); + //log_info("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); ppass->frag_shader = gl_create_shader(GL_FRAGMENT_SHADER, shader_str); free(shader_str); @@ -495,7 +495,10 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, P_GET_UNIFM_LOC("u_borderc", unifm_borderc); P_GET_UNIFM_LOC("u_resolution", unifm_resolution); P_GET_UNIFM_LOC("tex_scr", unifm_tex_scr); - P_GET_UNIFM_LOC("tex_wnd", unifm_tex_wnd); + // We don't need this one anymore since we get + // the border color using glReadPixel + // uncomment if you need to use 'tex_wnd' in the shader + //P_GET_UNIFM_LOC("tex_wnd", unifm_tex_wnd); #undef P_GET_UNIFM_LOC } @@ -536,7 +539,8 @@ bool glx_init_rounded_corners(session_t *ps) { " // Get the window_bg color (so we can \"erase\" corners) from the bg texture\n" " // and the border color from the mid x-axis of the target window (hacky...)\n" " vec4 u_v4WndBgColor = %s(tex_scr, vec2(gl_TexCoord[0].st));\n" - " vec4 u_v4BorderColor = %s(tex_wnd, vec2(0, u_texsize.t/2.));\n" + " //vec4 u_v4BorderColor = %s(tex_wnd, vec2(0, u_texsize.t/2.));\n" + " vec4 u_v4BorderColor = u_borderc;\n" " vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect, transparent\n" " vec4 v4FromColor = u_v4BorderColor; //Always the border color. If no border, this still should be set\n" " vec4 v4ToColor = u_v4WndBgColor; //Outside corners color, we set it to background texture\n" @@ -576,7 +580,8 @@ bool glx_init_rounded_corners(session_t *ps) { // dst1 shader static const char *FRAG_SHADER_ROUND_CORNERS_1 = " float u_fRadiusPx = u_radius + 25.0;\n" - " float u_fHalfBorderThickness = 20.0 /2.0;\n" + " float u_fHalfBorderThickness = u_borderw / 2.0;\n" + " //float u_fHalfBorderThickness = 20.0 /2.0;\n" " //u_v4FillColor = vec4(0.0, 1.0, 0.0, 1.0);\n" " //v4FromColor = u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" " //v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color\n" @@ -1232,6 +1237,34 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, } +bool glx_read_border_pixel(session_t *ps, struct managed_win *w, int x, int y, int width attr_unused, int height, float *ppixel) +{ + if (!ppixel) return false; + + // First try bottom left corner + auto openglx = x; + auto opengly = ps->root_height-height-y; + + // bottom left corner is out of bounds + // use top border line instead + if (openglx < 0 && opengly < 0) { + //openglx = x + width; + opengly += height-1; + } + + // Invert Y-axis so we can query border color from texture (0,0) + glReadPixels((openglx < 0) ? 0 : openglx, (opengly < 0) ? 0 : opengly, 1, 1, + GL_RGBA, GL_FLOAT, (void*)&w->border_col[0]); + + //log_warn("xy(%d, %d), glxy(%d %d) wh(%d %d), border_col(%.2f, %.2f, %.2f, %.2f)", + // x, y, openglx, opengly, width, height, + // (float)w->border_col[0], (float)w->border_col[1], (float)w->border_col[2], (float)w->border_col[3]); + + gl_check_err(); + + return true; +} + bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex attr_unused, int shader_idx, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { @@ -1242,18 +1275,14 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); bool ret = false; - - GLfloat border_col[4] = {0}; - - if (w->g.border_width >= 1) { - glReadPixels(dx, dy+height, 1, 1, GL_RGBA, GL_FLOAT, (void*)&border_col[0]); - //log_warn("border_col(%.2f, %.2f, %.2f, %.2f)", - // (float)border_col[0], (float)border_col[1], (float)border_col[2], (float)border_col[3]); - } //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) bw(%d)", // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width); + if (w->g.border_width >= 1 && w->border_col[0] == -1.0) { + glx_read_border_pixel(ps, w, dx, dy, width, height, &w->border_col[0]); + } + // Calculate copy region size glx_blur_cache_t ibc = {.width = 0, .height = 0}; if (!pbc) @@ -1350,9 +1379,9 @@ bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_text if (ppass->unifm_texsize >= 0) glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); if (ppass->unifm_borderw >= 0) - glUniform1f(ppass->unifm_borderw, w->g.border_width); + glUniform1f(ppass->unifm_borderw, (w->border_col[0] != -1.) ? w->g.border_width : 0); if (ppass->unifm_borderc >= 0) - glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&border_col[0]); + glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&w->border_col[0]); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); @@ -1436,11 +1465,9 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text assert(ps->psglx->round_passes[0].prog); assert(ps->psglx->round_passes[1].prog); bool ret = false; - - GLfloat border_col[4] = {0}; - if (w->g.border_width >= 1) { - glReadPixels(dx, dy+height, 1, 1, GL_RGBA, GL_FLOAT, (void*)&border_col[0]); + if (w->g.border_width >= 1 && w->border_col[0] == -1.0) { + glx_read_border_pixel(ps, w, dx, dy, width, height, &w->border_col[0]); } { @@ -1471,9 +1498,9 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text if (ppass->unifm_texsize >= 0) glUniform2f(ppass->unifm_texsize, (float)width, (float)height); if (ppass->unifm_borderw >= 0) - glUniform1f(ppass->unifm_borderw, w->g.border_width); + glUniform1f(ppass->unifm_borderw, (w->border_col[0] != -1.) ? w->g.border_width : 0); if (ppass->unifm_borderc >= 0) - glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&border_col[0]); + glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&w->border_col[0]); if (ppass->unifm_resolution >= 0) glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); diff --git a/src/picom.c b/src/picom.c index 82590207ff..251a0d7339 100644 --- a/src/picom.c +++ b/src/picom.c @@ -694,6 +694,9 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { w->frame_opacity = 1.0; } + // The below moved to it's own function: + // `win_determine_rounded_corners` (win.c) + /* // Don't round full screen windows & excluded windows if ((w && win_is_fullscreen(ps, w)) || c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) { @@ -701,6 +704,7 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { } else { w->corner_radius = ps->o.corner_radius; } + */ // Update window mode w->mode = win_calc_mode(ps, w); diff --git a/src/win.c b/src/win.c index d6ae90b0ed..d9faa4ad35 100644 --- a/src/win.c +++ b/src/win.c @@ -894,6 +894,28 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w) win_set_blur_background(ps, w, blur_background_new); } +/** + * Determine if a window should have rounded corners. + */ +static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) { + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE || ps->o.corner_radius == 0) + return; + + // Don't round full screen windows & excluded windows + if ((w && win_is_fullscreen(ps, w)) || + c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) { + w->corner_radius = 0; + //log_warn("xy(%d %d) wh(%d %d) will NOT round corners", w->g.x, w->g.y, w->widthb, w->heightb); + } else { + w->corner_radius = ps->o.corner_radius; + //log_warn("xy(%d %d) wh(%d %d) will round corners", w->g.x, w->g.y, w->widthb, w->heightb); + // HACK: we reset this so we can query the color once + // we query the color in glx_round_corners_dst0 using glReadPixels + //w->border_col = { -1., -1, -1, -1 }; + w->border_col[0] = w->border_col[1] = w->border_col[2] = w->border_col[3] = -1.0; + } +} + /** * Update window opacity according to opacity rules. */ @@ -927,6 +949,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) { win_determine_shadow(ps, w); win_determine_invert_color(ps, w); win_determine_blur_background(ps, w); + win_determine_rounded_corners(ps, w); win_update_opacity_rule(ps, w); if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) w->paint_excluded = c2_match(ps, w, ps->o.paint_blacklist, NULL); @@ -2123,6 +2146,7 @@ void map_win_start(session_t *ps, struct managed_win *w) { w->opacity, w->opacity_target); win_determine_blur_background(ps, w); + win_determine_rounded_corners(ps, w); // Cannot set w->ever_damaged = false here, since window mapping could be // delayed, so a damage event might have already arrived before this function diff --git a/src/win.h b/src/win.h index 34176446a3..4edd1a5ee8 100644 --- a/src/win.h +++ b/src/win.h @@ -204,6 +204,7 @@ struct managed_win { /// Corner radius int corner_radius; + float border_col[4]; // Fading-related members /// Override value of window fade state. Set by D-Bus method calls. From 1f8eb20d88803d651fa4dd911214198dd6e8a14a Mon Sep 17 00:00:00 2001 From: Samuel Hand Date: Sun, 5 Apr 2020 21:12:50 +0100 Subject: [PATCH 35/38] Fix a type error in the rounded corners shader --- src/opengl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opengl.c b/src/opengl.c index 2f7e185105..912ba19bfe 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -567,7 +567,7 @@ bool glx_init_rounded_corners(session_t *ps) { " } else {\n" " v4FromColor = u_v4FillColor;\n" " }\n" - " float fBlendAmount = clamp(fDist + 0.5, 0, 1);\n" + " float fBlendAmount = clamp(fDist + 0.5, 0.0, 1.0);\n" " //vec4 c = fDist <= 0.0 ? v4FromColor : v4ToColor;\n" " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);\n" "\n" @@ -598,7 +598,7 @@ bool glx_init_rounded_corners(session_t *ps) { " } else {\n" " v4FromColor = u_v4FillColor;\n" " }\n" - " float fBlendAmount = clamp(fDist + 0.5, 0, 1);\n" + " float fBlendAmount = clamp(fDist + 0.5, 0.0, 1.0);\n" " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" "\n" " // final color\n" From f6fa3c4d94c4664f2aca171c79ddbf0a834b8783 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Tue, 5 May 2020 16:16:06 -0700 Subject: [PATCH 36/38] merge with ibhagwan's fork commit 68c8f1b --- man/picom.1.asciidoc | 6 + src/backend/backend.c | 19 ++ src/backend/backend.h | 19 ++ src/backend/dummy/dummy.c | 23 ++ src/backend/gl/gl_common.c | 380 ++++++++++++++++++++++++++++++++++ src/backend/gl/gl_common.h | 19 ++ src/backend/gl/glx.c | 4 + src/backend/xrender/xrender.c | 26 +++ src/common.h | 4 + src/config.c | 3 +- src/config.h | 4 + src/config_libconfig.c | 5 + src/opengl.c | 294 ++++---------------------- src/opengl.h | 6 +- src/options.c | 10 + src/picom.c | 19 ++ src/render.c | 22 +- src/win.c | 5 + src/win.h | 1 + 19 files changed, 599 insertions(+), 270 deletions(-) diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index 112ac3b6a7..3f2f26c6cc 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -112,6 +112,12 @@ OPTIONS *--rounded-corners-exclude* 'CONDITION':: Exclude conditions for rounded corners. +*--round-borders* 'VALUE':: + When rounding corners, Round the borders of windows. (defaults to 1). + +*--round-borders-exclude* 'CONDITION':: + Exclude conditions for rounding borders. + *--mark-wmwin-focused*:: Try to detect WM windows (a non-override-redirect window with no child that has 'WM_STATE') and mark them as active. diff --git a/src/backend/backend.c b/src/backend/backend.c index 3a170e5e7a..1143e14a52 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -190,6 +190,17 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ®_paint_in_bound, ®_visible); } + // Store the window background for rounded corners + // If rounded corners backup the region first + if (w->corner_radius > 0) { + const int16_t x = w->g.x; + const int16_t y = w->g.y; + const auto wid = to_u16_checked(w->widthb); + const auto hei = to_u16_checked(w->heightb); + ps->backend_data->ops->store_back_texture(ps->backend_data, w, + ps->backend_round_context, ®_bound, x, y, wid, hei); + } + // Blur window background // TODO since the background might change the content of the window (e.g. // with shaders), we should consult the background whether the window @@ -378,6 +389,14 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { pixman_region32_fini(®_visible_local); pixman_region32_fini(®_bound_local); } + + // Round the corners as last step after blur/shadow/dim/etc + if (w->corner_radius > 0.0) { + ps->backend_data->ops->round(ps->backend_data, w, + ps->backend_round_context, w->win_image, + ®_bound, ®_visible); + } + pixman_region32_fini(®_bound); pixman_region32_fini(®_paint_in_bound); } diff --git a/src/backend/backend.h b/src/backend/backend.h index c1fa31c240..486ce69755 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -68,6 +68,11 @@ struct kernel_blur_args { int kernel_count; }; +struct round_corners_args { + int corner_radius; + bool round_borders; +}; + struct backend_operations { // =========== Initialization =========== @@ -140,6 +145,11 @@ struct backend_operations { const region_t *reg_blur, const region_t *reg_visible) attr_nonnull(1, 3, 4, 5); + /// Round a given region of the rendering buffer. + bool (*round)(backend_t *backend_data, struct managed_win *w, void *round_ctx, + void *image_data, const region_t *reg_round, const region_t *reg_visible) + attr_nonnull(1, 2, 3, 5, 6); + /// Update part of the back buffer with the rendering buffer, then present the /// back buffer onto the target window (if not back buffered, update part of the /// target window directly). @@ -221,6 +231,15 @@ struct backend_operations { /// Get how many pixels outside of the blur area is needed for blur void (*get_blur_size)(void *blur_context, int *width, int *height); + /// Backup our current window background so we can use it for "erasing" corners + bool (*store_back_texture)(backend_t *base, struct managed_win *w, void *ctx_, + const region_t *reg_tgt, int x, int y, int width, int height); + + /// Create a rounded corners context + void *(*create_round_context)(backend_t *base, void *args); + /// Destroy a rounded corners context + void (*destroy_round_context)(backend_t *base, void *ctx); + // =========== Hooks ============ /// Let the backend hook into the event handling queue /// Not implemented yet diff --git a/src/backend/dummy/dummy.c b/src/backend/dummy/dummy.c index dac08c2b6a..73f2b643bf 100644 --- a/src/backend/dummy/dummy.c +++ b/src/backend/dummy/dummy.c @@ -72,6 +72,12 @@ bool dummy_blur(struct backend_base *backend_data attr_unused, double opacity at return true; } +bool dummy_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused, + void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_round attr_unused, + const region_t *reg_visible attr_unused) { + return true; +} + void *dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned attr_unused) { auto dummy = (struct dummy_data *)base; @@ -138,6 +144,14 @@ void *dummy_create_blur_context(struct backend_base *base attr_unused, void dummy_destroy_blur_context(struct backend_base *base attr_unused, void *ctx attr_unused) { } +void *dummy_create_round_context(struct backend_base *base attr_unused, void *args attr_unused) { + static int dummy_context; + return &dummy_context; +} + +void dummy_destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) { +} + void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) { // These numbers are arbitrary, to make sure the reisze_region code path is // covered. @@ -145,12 +159,18 @@ void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) { *height = 5; } +bool dummy_store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused, + const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) { + return true; +} + struct backend_operations dummy_ops = { .init = dummy_init, .deinit = dummy_deinit, .compose = dummy_compose, .fill = dummy_fill, .blur = dummy_blur, + .round = dummy_round, .bind_pixmap = dummy_bind_pixmap, .render_shadow = default_backend_render_shadow, .release_image = dummy_release_image, @@ -162,6 +182,9 @@ struct backend_operations dummy_ops = { .copy = dummy_image_copy, .create_blur_context = dummy_create_blur_context, .destroy_blur_context = dummy_destroy_blur_context, + .create_round_context = dummy_create_round_context, + .destroy_round_context = dummy_destroy_round_context, .get_blur_size = dummy_get_blur_size, + .store_back_texture = dummy_store_back_texture }; diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 311fcc3a1b..2fffdb7d55 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -18,6 +18,7 @@ #include "string_utils.h" #include "types.h" #include "utils.h" +#include "win.h" #include "backend/backend_common.h" #include "backend/gl/gl_common.h" @@ -47,6 +48,20 @@ struct gl_blur_context { int npasses; }; +struct gl_round_context { + gl_round_shader_t *round_shader; + GLuint *bg_fbo; + GLuint *bg_tex; + /// Cached size of each blur_texture + struct tex_size { + int width; + int height; + } * tex_sizes; + int tex_count; + int fbo_count; + bool round_borders; +}; + static GLint glGetUniformLocationChecked(GLuint p, const char *name) { auto ret = glGetUniformLocation(p, name); if (ret < 0) { @@ -730,6 +745,182 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu return ret; } +bool gl_round(backend_t *backend_data attr_unused, struct managed_win *w, void *ctx_, void *image_data, + const region_t *reg_round attr_unused, const region_t *reg_visible attr_unused) { + + struct gl_round_context *cctx = ctx_; + auto gd = (struct gl_data *)backend_data; + auto img = (struct gl_image*)image_data; + + //log_warn("r(%d) b(%d), wxy(%d %d) wwh(%d %d) img(%d %d)", + // w->corner_radius, w->g.border_width, w->g.x, w->g.y, + // w->widthb, w->heightb, img->inner->width, img->inner->height); + + int nrects; + const rect_t *rects; + rects = pixman_region32_rectangles((region_t *)reg_round, &nrects); + if (!nrects) { + // Nothing to paint + return false; + } + + GLuint target = gd->back_fbo; + int dst_x = w->g.x; + int dst_y = w->g.y; + + auto coord = ccalloc(nrects * 16, GLint); + auto indices = ccalloc(nrects * 6, GLuint); + x_rect_to_coords(nrects, rects, dst_x, dst_y, + img ? img->inner->height : w->heightb, gd->height, + img ? img->inner->y_inverted : true, coord, indices); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint bo[2]; + glGenBuffers(2, bo); + glBindBuffer(GL_ARRAY_BUFFER, bo[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * nrects * 16, coord, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * nrects * 6, + indices, GL_STATIC_DRAW); + + glEnableVertexAttribArray(vert_coord_loc); + glEnableVertexAttribArray(vert_in_texcoord_loc); + glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 4, NULL); + glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE, + sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2)); + + // XXX: do we need projection matrix at all? + // Note: OpenGL matrices are column major + GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)gd->width, 0, 0, 0}, + {0, 2.0f / (GLfloat)gd->height, 0, 0}, + {0, 0, 0, 0}, + {-1, -1, 0, 1}}; + + //glDisable(GL_BLEND); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + // Bind texture + glViewport(0, 0, gd->width, gd->height); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, cctx->bg_tex[0]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, img ? img->inner->texture : gd->back_texture); + + const gl_round_shader_t *ppass = &cctx->round_shader[0]; + glUseProgram(ppass->prog); + + if (ppass->projection_loc >= 0) + glUniformMatrix4fv(ppass->projection_loc, 1, false, projection_matrix[0]); + if (ppass->unifm_tex_bg >= 0) + glUniform1i(ppass->unifm_tex_bg, (GLint)1); + if (ppass->unifm_radius) + glUniform1f(ppass->unifm_radius, (float)w->corner_radius); + if (ppass->unifm_texcoord) + glUniform2f(ppass->unifm_texcoord, (float)w->g.x, (float)w->g.y); + if (ppass->unifm_texsize) + glUniform2f(ppass->unifm_texsize, (float)w->widthb, (float)w->heightb); + if (ppass->unifm_borderw) + glUniform1f(ppass->unifm_borderw, (w->round_borders) ? w->g.border_width : 0); + if (ppass->unifm_resolution) + glUniform2f(ppass->unifm_resolution, (float)gd->width, (float)gd->height); + + // Draw + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target); + glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL); + glDisableVertexAttribArray(vert_coord_loc); + glDisableVertexAttribArray(vert_in_texcoord_loc); + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); + + // Cleanup + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDrawBuffer(GL_BACK); + glEnable(GL_BLEND); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDeleteBuffers(2, bo); + + glUseProgram(0); + gl_check_err(); + + free(indices); + free(coord); + + return true; +} + +// Assumes the two textures are the same dimensions +static bool copyFrameBufferTexture(int width, int height, GLuint fboIn, GLuint textureIn, GLuint fboOut, GLuint textureOut) +{ + bool ret = false; + + // Bind input FBO + texture to a color attachment + glBindFramebuffer(GL_READ_FRAMEBUFFER, fboIn); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureIn, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) { + log_error("Source framebuffer attachment failed."); + goto out; + } + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Bind destination FBO + texture to another color attachment + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboOut); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textureOut, 0); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) { + log_error("Destination framebuffer attachment failed."); + goto out; + } + glDrawBuffer(GL_COLOR_ATTACHMENT1); + + // specify source, destination drawing (sub)rectangles. + glBlitFramebuffer(0, 0, width, height, + 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + ret = true; + +out: + // unbind the color attachments + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + gl_check_err(); + + return ret; +} + +bool gl_store_back_texture(backend_t *backend_data attr_unused, + struct managed_win *w attr_unused, void *ctx_ attr_unused, + const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, + int width attr_unused, int height attr_unused) { + + struct gl_round_context *cctx = ctx_; + auto gd = (struct gl_data *)backend_data; + + //log_info("Copying xy(%d %d) wh(%d %d)", x, y, width, height); + + { + // Prepare our backup texture + glBindTexture(GL_TEXTURE_2D, cctx->bg_tex[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gd->width, + gd->height, 0, GL_BGR, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + copyFrameBufferTexture(gd->width, gd->height, gd->back_fbo, gd->back_texture, cctx->bg_fbo[0], cctx->bg_tex[0]); + } + + return true; +} + // clang-format off const char *vertex_shader = GLSL(330, uniform mat4 projection; @@ -975,6 +1166,36 @@ void gl_destroy_blur_context(backend_t *base attr_unused, void *ctx) { gl_check_err(); } +void gl_destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) { + + struct gl_round_context *cctx = ctx; + + if (cctx->round_shader && cctx->round_shader->prog) { + glDeleteProgram(cctx->round_shader->prog); + cctx->round_shader->prog = 0; + free(cctx->round_shader); + } + + if (cctx->bg_tex) { + glDeleteTextures(cctx->tex_count, cctx->bg_tex); + free(cctx->bg_tex); + } + if (cctx->bg_fbo) { + glDeleteFramebuffers(cctx->fbo_count, cctx->bg_fbo); + free(cctx->bg_fbo); + } + if (cctx->tex_sizes) { + free(cctx->tex_sizes); + } + + cctx->tex_count = 0; + cctx->fbo_count = 0; + + free(cctx); + + gl_check_err(); +} + /** * Initialize GL blur filters. */ @@ -1145,6 +1366,165 @@ void gl_get_blur_size(void *blur_context, int *width, int *height) { *height = ctx->resize_height; } +void *gl_create_round_context(struct backend_base *base attr_unused, void *args attr_unused) { + bool success; + auto gd = (struct gl_data *)base; + auto ctx = ccalloc(1, struct gl_round_context); + + struct round_corners_args *round_params = (struct round_corners_args *)args; + + ctx->round_borders = round_params->round_borders; + ctx->round_shader = ccalloc(1, gl_round_shader_t); + + char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL)); + // Enforce LC_NUMERIC locale "C" here to make sure decimal point is sane + // Thanks to hiciu for reporting. + setlocale(LC_NUMERIC, "C"); + + // Dual-kawase downsample shader / program + auto pass = ctx->round_shader; + { + // TEST passthrough shader + /*static const char frag_passthrough[] = GLSL(330, + uniform sampler2D tex; + in vec2 texcoord; + void main() { + //gl_FragColor = texture2D(tex, texcoord); + //gl_FragColor = vec4(texture2D(tex, vec2(texcoord.xy), 0).rgb, 1); + gl_FragColor = texelFetch(tex, ivec2(texcoord.xy), 0); + //gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + } + );*/ + + // dst0 shader from opengl.c + // clang-format off + static const char *FRAG_SHADER_ROUND_CORNERS = GLSL(330, + uniform sampler2D tex; + uniform sampler2D tex_bg; + uniform float u_radius; + uniform float u_borderw; + uniform vec2 u_texcoord; + uniform vec2 u_texsize; + uniform vec2 u_resolution; + in vec2 texcoord; + out vec4 out_color; + // https://www.shadertoy.com/view/ltS3zW + float RectSDF(vec2 p, vec2 b, float r) { + vec2 d = abs(p) - b + vec2(r); + return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r; + } + void main() { + vec2 coord = vec2(u_texcoord.x, u_resolution.y-u_texsize.y-u_texcoord.y); + vec4 u_v4WndBgColor = texelFetch(tex_bg, ivec2(gl_FragCoord.xy), 0); + vec4 u_v4BorderColor = texelFetch(tex, ivec2(0, 0), 0); + vec4 u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect, transparent + vec4 v4FromColor = u_v4BorderColor; // Always the border color. If no border, this still should be set + vec4 v4ToColor = u_v4WndBgColor; // Outside corners color = background texture + float u_fRadiusPx = u_radius; + float u_fHalfBorderThickness = u_borderw / 2.0; + + // misc tests, uncomment for diff rect colors + //u_v4FillColor = texture2D(tex, texcoord/u_texsize); + //u_v4FillColor = texelFetch(tex, ivec2(texcoord.xy), 0); + //u_v4FillColor = vec4(0.0, 1.0, 0.0, 0.0); // Inside rect color + //v4FromColor = u_v4BorderColor = vec4(1.0, 1.0, 0.0, 1.0); + //v4ToColor = vec4(0.0, 0.0, 1.0, 1.0); //Outside color + + vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness); + vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord); + + float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_fRadiusPx - u_fHalfBorderThickness); + if (u_fHalfBorderThickness > 0.0) { + if (fDist < 0.0) { + v4ToColor = u_v4FillColor; + } + fDist = abs(fDist) - u_fHalfBorderThickness; + } else { + v4FromColor = u_v4FillColor; + } + float fBlendAmount = smoothstep(-1.0, 1.0, fDist); + + // final color + vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount); + // we don't use discard due to alleged worse perf + // instead we can use alpha blending + //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else + out_color = c; + } + ); + // clang-format on + + // Build shader + const char* SHADER_STR = FRAG_SHADER_ROUND_CORNERS; + //const char* SHADER_STR = frag_passthrough; + size_t shader_len = strlen(SHADER_STR) + 1 /* null terminator */; + char *shader_str = ccalloc(shader_len, char); + auto real_shader_len = snprintf(shader_str, shader_len, "%s", SHADER_STR); + CHECK(real_shader_len >= 0); + CHECK((size_t)real_shader_len < shader_len); + + // Build program + pass->prog = gl_create_program_from_str(vertex_shader, shader_str); + free(shader_str); + if (!pass->prog) { + log_error("Failed to create GLSL program."); + success = false; + goto out; + } + glBindFragDataLocation(pass->prog, 0, "out_color"); + + // Get uniform addresses + pass->projection_loc = glGetUniformLocationChecked(pass->prog, "projection"); + pass->unifm_tex_bg = glGetUniformLocationChecked(pass->prog, "tex_bg"); + pass->unifm_radius = glGetUniformLocationChecked(pass->prog, "u_radius"); + pass->unifm_texcoord = glGetUniformLocationChecked(pass->prog, "u_texcoord"); + pass->unifm_texsize = glGetUniformLocationChecked(pass->prog, "u_texsize"); + pass->unifm_borderw = glGetUniformLocationChecked(pass->prog, "u_borderw"); + pass->unifm_resolution = glGetUniformLocationChecked(pass->prog, "u_resolution"); + } + + // Texture size will be defined by gl_round + ctx->tex_count = 1; + ctx->bg_tex = ccalloc(ctx->tex_count, GLuint); + ctx->tex_sizes = ccalloc(ctx->tex_count, struct tex_size); + glGenTextures(ctx->tex_count, ctx->bg_tex); + for (int i = 0; i < ctx->tex_count; ++i) { + glBindTexture(GL_TEXTURE_2D, ctx->bg_tex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + // Generate FBO and textures when needed + ctx->fbo_count = 1; + ctx->bg_fbo = ccalloc(ctx->fbo_count, GLuint); + glGenFramebuffers(ctx->fbo_count, ctx->bg_fbo); + for (int i = 0; i < ctx->fbo_count; ++i) { + if (!ctx->bg_fbo[i]) { + log_error("Failed to generate framebuffer object for blur"); + success = false; + goto out; + } + } + + success = true; + +out: + + // Restore LC_NUMERIC + setlocale(LC_NUMERIC, lc_numeric_old); + free(lc_numeric_old); + + if (!success) { + gl_destroy_round_context(&gd->base, ctx); + ctx = NULL; + } + + gl_check_err(); + return ctx; +} + // clang-format off const char *win_shader_glsl = GLSL(330, uniform float opacity; diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 3696a6ab0c..6a178b9d94 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -37,6 +37,18 @@ typedef struct { GLint texorig_loc; } gl_blur_shader_t; +typedef struct { + GLuint prog; + GLint projection_loc; + GLint unifm_radius; + GLint unifm_texcoord; + GLint unifm_texsize; + GLint unifm_borderw; + GLint unifm_resolution; + GLint unifm_tex_bg; + GLint unifm_tex_wnd; +} gl_round_shader_t; + typedef struct { GLuint prog; GLint color_loc; @@ -121,6 +133,13 @@ void *gl_create_blur_context(backend_t *base, enum blur_method, void *args); void gl_destroy_blur_context(backend_t *base, void *ctx); void gl_get_blur_size(void *blur_context, int *width, int *height); +bool gl_round(backend_t *backend_data, struct managed_win *w, void *ctx_, + void *image_data, const region_t *reg_round, const region_t *reg_visible); +void *gl_create_round_context(backend_t *base, void *args); +void gl_destroy_round_context(backend_t *base, void *ctx); +bool gl_store_back_texture(backend_t *backend_data, struct managed_win *w, + void *ctx_, const region_t *reg_tgt, int x, int y, int width, int height); + bool gl_is_image_transparent(backend_t *base, void *image_data); void gl_fill(backend_t *base, struct color, const region_t *clip); diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index ac066199f8..6d710771df 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -492,6 +492,7 @@ struct backend_operations glx_ops = { .image_op = gl_image_op, .copy = gl_copy, .blur = gl_blur, + .round = gl_round, .is_image_transparent = gl_is_image_transparent, .present = glx_present, .buffer_age = glx_buffer_age, @@ -499,7 +500,10 @@ struct backend_operations glx_ops = { .fill = gl_fill, .create_blur_context = gl_create_blur_context, .destroy_blur_context = gl_destroy_blur_context, + .create_round_context = gl_create_round_context, + .destroy_round_context = gl_destroy_round_context, .get_blur_size = gl_get_blur_size, + .store_back_texture = gl_store_back_texture, .max_buffer_age = 5, // Why? }; diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index db540ae985..0dd3b08640 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -290,6 +290,15 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, return true; } +static bool x_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused, + void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_blur attr_unused, + const region_t *reg_visible attr_unused) { + + // dummy implementation, we already perform the rounding in compose + // TODO: should move the compose code here and call it from here + return true; +} + static void * bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { xcb_generic_error_t *e; @@ -596,6 +605,19 @@ void get_blur_size(void *blur_context, int *width, int *height) { *height = ctx->resize_height; } +bool store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused, + const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) { + return true; +} + +void *create_round_context(struct backend_base *base attr_unused, void *args attr_unused) { + static int dummy_context; + return &dummy_context; +} + +void destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) { +} + backend_t *backend_xrender_init(session_t *ps) { auto xd = ccalloc(1, struct _xrender_data); init_backend_base(&xd->base, ps); @@ -683,6 +705,7 @@ struct backend_operations xrender_ops = { .init = backend_xrender_init, .deinit = deinit, .blur = blur, + .round = x_round, .present = present, .compose = compose, .fill = fill, @@ -699,7 +722,10 @@ struct backend_operations xrender_ops = { .copy = copy, .create_blur_context = create_blur_context, .destroy_blur_context = destroy_blur_context, + .create_round_context = create_round_context, + .destroy_round_context = destroy_round_context, .get_blur_size = get_blur_size, + .store_back_texture = store_back_texture }; // vim: set noet sw=8 ts=8: diff --git a/src/common.h b/src/common.h index 84a42ceb4a..1b75f6bd74 100644 --- a/src/common.h +++ b/src/common.h @@ -157,6 +157,8 @@ typedef struct session { backend_t *backend_data; /// backend blur context void *backend_blur_context; + /// round corners context + void *backend_round_context; /// graphic drivers used enum driver drivers; /// file watch handle @@ -340,11 +342,13 @@ typedef struct session { /// Whether X Present extension exists. bool present_exists; /// Whether X GLX extension exists. +#ifdef CONFIG_OPENGL bool glx_exists; /// Event base number for X GLX extension. int glx_event; /// Error base number for X GLX extension. int glx_error; +#endif /// Whether X Xinerama extension exists. bool xinerama_exists; /// Xinerama screen regions. diff --git a/src/config.c b/src/config.c index f24963595f..30f0dd27d9 100644 --- a/src/config.c +++ b/src/config.c @@ -561,7 +561,8 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .track_leader = false, - .rounded_corners_blacklist = NULL + .rounded_corners_blacklist = NULL, + .round_borders_blacklist = NULL }; char *ret = NULL; diff --git a/src/config.h b/src/config.h index ae0aa97fd0..e237f497fb 100644 --- a/src/config.h +++ b/src/config.h @@ -241,6 +241,10 @@ typedef struct options { int corner_radius; /// Rounded corners blacklist. A linked list of conditions. c2_lptr_t *rounded_corners_blacklist; + /// Do we round the borders of rounded windows? + int round_borders; + /// Rounded borders blacklist. A linked list of conditions. + c2_lptr_t *round_borders_blacklist; } options_t; extern const char *const BACKEND_STRS[NUM_BKEND + 1]; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 4295fb1778..c7ab438cc0 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -371,6 +371,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad config_lookup_int(&cfg, "corner-radius", &opt->corner_radius); // --rounded-corners-exclude parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude"); + // --round-borders + config_lookup_int(&cfg, "round-borders", &opt->round_borders); + // --round-borders-exclude + parse_cfg_condlst(&cfg, &opt->round_borders_blacklist, "round-borders-exclude"); // -e (frame_opacity) config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); // -c (shadow_enable) @@ -450,6 +454,7 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad } lcfg_lookup_bool(&cfg, "vsync", &opt->vsync); // --backend + lcfg_lookup_bool(&cfg, "experimental-backends", &opt->experimental_backends); if (config_lookup_string(&cfg, "backend", &sval)) { opt->backend = parse_backend(sval); if (opt->backend >= NUM_BKEND) { diff --git a/src/opengl.c b/src/opengl.c index 912ba19bfe..74e19eb187 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -455,7 +455,7 @@ static inline bool glx_init_frag_shader_corners(glx_round_pass_t *ppass, pc += strlen(pc); assert(strlen(shader_str) < len); - sprintf(pc, SHADER_STR); + sprintf(pc, "%s", SHADER_STR); assert(strlen(shader_str) < len); #ifdef DEBUG_GLX log_debug("Generated rounded corners shader %d:\n%s\n", shader_idx, shader_str); @@ -546,40 +546,10 @@ bool glx_init_rounded_corners(session_t *ps) { " vec4 v4ToColor = u_v4WndBgColor; //Outside corners color, we set it to background texture\n" "\n"; - // Fragment shader (round corners) - // dst0 shader - static const char *FRAG_SHADER_ROUND_CORNERS_0 = - " float u_fRadiusPx = u_radius;\n" - " float u_fHalfBorderThickness = u_borderw / 2.0;\n" - " //v4FromColor = u_v4BorderColor = vec4(1.0, 0.0, 0.0, 1.0);\n" - " //u_v4FillColor = vec4(0.0, 0.0, 0.0, 0.0); // Inside rect color\n" - - "\n" - " vec2 u_v2HalfShapeSizePx = u_texsize/2.0 - vec2(u_fHalfBorderThickness);\n" - " vec2 v_v2CenteredPos = (gl_FragCoord.xy - u_texsize.xy / 2.0 - coord);\n" - "\n" - " float fDist = RectSDF(v_v2CenteredPos, u_v2HalfShapeSizePx, u_fRadiusPx - u_fHalfBorderThickness);\n" - " if (u_fHalfBorderThickness > 0.0) {\n" - " if (fDist < 0.0) {\n" - " v4ToColor = u_v4FillColor;\n" - " }\n" - " fDist = abs(fDist) - u_fHalfBorderThickness;\n" - " } else {\n" - " v4FromColor = u_v4FillColor;\n" - " }\n" - " float fBlendAmount = clamp(fDist + 0.5, 0.0, 1.0);\n" - " //vec4 c = fDist <= 0.0 ? v4FromColor : v4ToColor;\n" - " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);\n" - "\n" - " // final color\n" - " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" - " gl_FragColor = c;\n" - "}\n"; - // Fragment shader (round corners) // dst1 shader - static const char *FRAG_SHADER_ROUND_CORNERS_1 = - " float u_fRadiusPx = u_radius + 25.0;\n" + static const char *FRAG_SHADER_ROUND_CORNERS = + " float u_fRadiusPx = u_radius;\n" " float u_fHalfBorderThickness = u_borderw / 2.0;\n" " //float u_fHalfBorderThickness = 20.0 /2.0;\n" " //u_v4FillColor = vec4(0.0, 1.0, 0.0, 1.0);\n" @@ -598,11 +568,11 @@ bool glx_init_rounded_corners(session_t *ps) { " } else {\n" " v4FromColor = u_v4FillColor;\n" " }\n" - " float fBlendAmount = clamp(fDist + 0.5, 0.0, 1.0);\n" + " float fBlendAmount = smoothstep(-1.0, 1.0, fDist);\n" " vec4 c = mix(v4FromColor, v4ToColor, fBlendAmount);" "\n" " // final color\n" - " if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" + " //if ( c == vec4(0.0,0.0,0.0,0.0) ) discard; else\n" " gl_FragColor = c;\n" " //gl_FragColor = vec4(vec3(fBlendAmount), 1.0);\n" " //gl_FragColor = vec4(vec3(abs(dist) / (2.0 * corner)), 1.0);\n" @@ -621,7 +591,7 @@ bool glx_init_rounded_corners(session_t *ps) { } if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[0], 0, - FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_0, + FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS, extension, sampler_type, texture_func)) { log_error("Failed to create rounded corners fragment shader PRE."); @@ -631,17 +601,6 @@ bool glx_init_rounded_corners(session_t *ps) { return false; } - if (!glx_init_frag_shader_corners(&ps->psglx->round_passes[1], 1, - FRAG_SHADER_PREFIX, FRAG_SHADER_ROUND_CORNERS_1, - extension, sampler_type, texture_func)) { - - log_error("Failed to create rounded corners fragment shader POST."); - setlocale(LC_NUMERIC, lc_numeric_old); - free(lc_numeric_old); - free(extension); - return false; - } - free(extension); // Restore LC_NUMERIC @@ -715,7 +674,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, glx_texture_t *ptex = *pptex; - //log_trace("Copying xy(%d %d) wh(%d %d)", x, y, width, height); + //log_trace("Copying xy(%d %d) wh(%d %d) ptex(%p)", x, y, width, height, ptex); // Release texture if parameters are inconsistent if (ptex && ptex->texture && @@ -1236,20 +1195,41 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, return ret; } - -bool glx_read_border_pixel(session_t *ps, struct managed_win *w, int x, int y, int width attr_unused, int height, float *ppixel) +// TODO: this is a mess and needs a more consistent way of getting the border pixel +// I tried looking for a notify event for XCB_CW_BORDER_PIXEL (in xcb_create_window()) +// or a way to get the pixels from xcb_render_picture_t but the documentation for +// the xcb_xrender extension is literaly non existent... +bool glx_read_border_pixel(struct managed_win *w, int root_height, int x, int y, + int width attr_unused, int height, int cr, float *ppixel) { if (!ppixel) return false; - // First try bottom left corner - auto openglx = x; - auto opengly = ps->root_height-height-y; + // First try bottom left corner past the + // circle radius (after the rounded corner ends) + auto openglx = x + cr*2; + auto opengly = root_height-height-y; + + // X is out of bounds + // move to the right side + if (openglx < 0) + openglx = x + width - cr; + + // Y is out of bounds + // move to to top part + if (opengly < 0) { + opengly += height-1; + } // bottom left corner is out of bounds // use top border line instead - if (openglx < 0 && opengly < 0) { - //openglx = x + width; - opengly += height-1; + if (openglx < 0 || opengly < 0) { + + //log_warn("OUT OF BOUNDS: xy(%d, %d), glxy(%d %d) wh(%d %d), border_col(%.2f, %.2f, %.2f, %.2f)", + // x, y, openglx, opengly, width, height, + // (float)w->border_col[0], (float)w->border_col[1], (float)w->border_col[2], (float)w->border_col[3]); + + // Reset the color so the shader doesn't use it + w->border_col[0] = w->border_col[1] = w->border_col[2] = w->border_col[3] = -1.0; } // Invert Y-axis so we can query border color from texture (0,0) @@ -1265,199 +1245,7 @@ bool glx_read_border_pixel(session_t *ps, struct managed_win *w, int x, int y, i return true; } -bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex attr_unused, int shader_idx, - int dx, int dy, int width, int height, float z, float cr, - const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc) { - - assert(shader_idx >= 0 && shader_idx <= 1); - assert(ps->psglx->round_passes[0].prog); - assert(ps->psglx->round_passes[1].prog); - const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); - const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); - bool ret = false; - - //log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) bw(%d)", - // dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width); - - if (w->g.border_width >= 1 && w->border_col[0] == -1.0) { - glx_read_border_pixel(ps, w, dx, dy, width, height, &w->border_col[0]); - } - - // 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; - // log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight); - - GLenum tex_tgt = GL_TEXTURE_RECTANGLE; - if (ps->psglx->has_texture_non_power_of_two) - tex_tgt = GL_TEXTURE_2D; - - // Free textures if size inconsistency discovered - if (mwidth != pbc->width || mheight != pbc->height) - free_glx_bc_resize(ps, pbc); - - // Generate FBO and textures if needed - if (!pbc->textures[0]) - pbc->textures[0] = glx_gen_texture(tex_tgt, mwidth, mheight); - GLuint tex_scr = pbc->textures[0]; - - pbc->width = mwidth; - pbc->height = mheight; - - if (!tex_scr) { - log_error("Failed to allocate texture."); - goto glx_round_corners_dst_end; - } - - // 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); - - // Texture scaling factor - GLfloat texfac_x = 1.0f, texfac_y = 1.0f; - if (tex_tgt == GL_TEXTURE_2D) { - texfac_x /= (GLfloat)mwidth; - texfac_y /= (GLfloat)mheight; - } - - // Paint it back - { - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - } - - { - const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; - assert(ppass->prog); - - assert(tex_scr); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(tex_tgt, tex_scr); - - // If caller specified a texture use it as source - if (ptex) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(ptex->target, ptex->texture); - } else { - glActiveTexture(GL_TEXTURE0); - glBindTexture(tex_tgt, tex_scr); - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDrawBuffer(GL_BACK); - if (have_scissors) - glEnable(GL_SCISSOR_TEST); - if (have_stencil) - glEnable(GL_STENCIL_TEST); - - - // Our shader generates a transparent mid section - // with opaque corners copied from the background texture - // We must use blending to get the window pixesl to appear - //glDisable(GL_BLEND); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - - glUseProgram(ppass->prog); - - if (ppass->unifm_tex_scr >= 0) - glUniform1i(ppass->unifm_tex_scr, (GLint)0); - if (ppass->unifm_tex_wnd >= 0) - glUniform1i(ppass->unifm_tex_wnd, (GLint)1); - - if (ppass->unifm_radius >= 0) - glUniform1f(ppass->unifm_radius, cr); - if (ppass->unifm_texcoord >= 0) - glUniform2f(ppass->unifm_texcoord, (float)dx, (float)dy); - if (ppass->unifm_texsize >= 0) - glUniform2f(ppass->unifm_texsize, (float)mwidth, (float)mheight); - if (ppass->unifm_borderw >= 0) - glUniform1f(ppass->unifm_borderw, (w->border_col[0] != -1.) ? w->g.border_width : 0); - if (ppass->unifm_borderc >= 0) - glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&w->border_col[0]); - if (ppass->unifm_resolution >= 0) - glUniform2f(ppass->unifm_resolution, (float)ps->root_width, (float)ps->root_height); - - // Painting - { - P_PAINTREG_START(crect) { - // XXX explain these variables - auto rx = (GLfloat)(crect.x1 - dx); - auto ry = (GLfloat)(crect.y1 - dy); - auto rxe = rx + (GLfloat)(crect.x2 - crect.x1); - auto rye = ry + (GLfloat)(crect.y2 - crect.y1); - // Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] - // [0-1] Thanks to amonakov for pointing out! - if (GL_TEXTURE_2D == tex_tgt) { - rx = rx / (GLfloat)width; - ry = ry / (GLfloat)height; - rxe = rxe / (GLfloat)width; - rye = rye / (GLfloat)height; - } - auto rdx = (GLfloat)crect.x1; - auto rdy = (GLfloat)(ps->root_height - crect.y1); - auto rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1); - auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1); - - // Invert Y if needed, this may not work as expected, though. I - // don't have such a FBConfig to test with. - //if (ptex && !ptex->y_inverted) { - { - ry = 1.0f - ry; - rye = 1.0f - rye; - } - - //log_trace("Rect %d (i:%d): %f, %f, %f, %f -> %f, %f, %f, %f", - // ri ,ptex ? ptex->y_inverted : -1, rx, ry, rxe, rye, rdx, rdy, rdxe, rdye); - - glTexCoord2f(rx, ry); - glVertex3f(rdx, rdy, z); - - glTexCoord2f(rxe, ry); - glVertex3f(rdxe, rdy, z); - - glTexCoord2f(rxe, rye); - glVertex3f(rdxe, rdye, z); - - glTexCoord2f(rx, rye); - glVertex3f(rdx, rdye, z); - - } - P_PAINTREG_END(); - } - - glUseProgram(0); - glDisable(GL_BLEND); - } - - ret = true; - -glx_round_corners_dst_end: - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(tex_tgt, 0); - 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); - } - - gl_check_err(); - - return ret; -} - -bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { @@ -1466,12 +1254,12 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text assert(ps->psglx->round_passes[1].prog); bool ret = false; - if (w->g.border_width >= 1 && w->border_col[0] == -1.0) { - glx_read_border_pixel(ps, w, dx, dy, width, height, &w->border_col[0]); + if (w->g.border_width >= 1 /*&& w->border_col[0] == -1.0*/) { + glx_read_border_pixel(w, ps->root_height, dx, dy, width, height, w->corner_radius, &w->border_col[0]); } { - const glx_round_pass_t *ppass = &ps->psglx->round_passes[shader_idx]; + const glx_round_pass_t *ppass = &ps->psglx->round_passes[0]; assert(ppass->prog); // If caller specified a texture use it as source @@ -1498,7 +1286,7 @@ bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_text if (ppass->unifm_texsize >= 0) glUniform2f(ppass->unifm_texsize, (float)width, (float)height); if (ppass->unifm_borderw >= 0) - glUniform1f(ppass->unifm_borderw, (w->border_col[0] != -1.) ? w->g.border_width : 0); + glUniform1f(ppass->unifm_borderw, (w->round_borders && w->border_col[0] != -1.) ? w->g.border_width : 0); if (ppass->unifm_borderc >= 0) glUniform4fv(ppass->unifm_borderc, 1, (GLfloat *)&w->border_col[0]); if (ppass->unifm_resolution >= 0) diff --git a/src/opengl.h b/src/opengl.h index 8475bc6672..0c8dfac412 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -137,14 +137,10 @@ void glx_set_clip(session_t *ps, const region_t *reg); bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, +bool glx_round_corners_dst(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt, glx_blur_cache_t *pbc); -bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, - int dx, int dy, int width, int height, float z, float cr, - const region_t *reg_tgt, glx_blur_cache_t *pbc); - GLuint glx_create_shader(GLenum shader_type, const char *shader_str); GLuint glx_create_program(const GLuint *const shaders, int nshaders); diff --git a/src/options.c b/src/options.c index 6c067e7189..ec370c2469 100644 --- a/src/options.c +++ b/src/options.c @@ -120,6 +120,12 @@ static void usage(const char *argv0, int ret) { "--rounded-corners-exclude condition\n" " Exclude conditions for rounded corners.\n" "\n" + "--round-borders value\n" + " When rounding corners, round the borders of windows. (defaults to 1)\n" + "\n" + "--round-borders-exclude condition\n" + " Exclude conditions for rounding borders.\n" + "\n" "--mark-wmwin-focused\n" " Try to detect WM windows and mark them as active.\n" "\n" @@ -445,6 +451,8 @@ static const struct option longopts[] = { {"blur-deviation", required_argument, NULL, 330}, {"corner-radius", required_argument, NULL, 331}, {"rounded-corners-exclude", required_argument, NULL, 332}, + {"round-borders", required_argument, NULL, 334}, + {"round-borders-exclude", required_argument, NULL, 335}, {"experimental-backends", no_argument, NULL, 733}, {"monitor-repaint", no_argument, NULL, 800}, {"diagnostics", no_argument, NULL, 801}, @@ -852,6 +860,8 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, case 331: opt->corner_radius = atoi(optarg); break; case 332: condlst_add(&opt->rounded_corners_blacklist, optarg); break; + case 334: opt->round_borders = atoi(optarg); break; + case 335: condlst_add(&opt->round_borders_blacklist, optarg); break; P_CASEBOOL(733, experimental_backends); P_CASEBOOL(800, monitor_repaint); case 801: opt->print_diagnostics = true; break; diff --git a/src/picom.c b/src/picom.c index 251a0d7339..95ccbb6713 100644 --- a/src/picom.c +++ b/src/picom.c @@ -484,6 +484,16 @@ static bool initialize_blur(session_t *ps) { return ps->backend_blur_context != NULL; } + +static bool initialize_round_corners(session_t *ps) { + struct round_corners_args cargs; + cargs.corner_radius = ps->o.corner_radius; + cargs.round_borders = ps->o.round_borders; + ps->backend_round_context = ps->backend_data->ops->create_round_context( + ps->backend_data, &cargs); + return ps->backend_round_context != NULL; +} + /// Init the backend and bind all the window pixmap to backend images static bool initialize_backend(session_t *ps) { if (ps->o.experimental_backends) { @@ -506,6 +516,11 @@ static bool initialize_backend(session_t *ps) { return false; } + if (!initialize_round_corners(ps)) { + log_fatal("Failed to prepare for rounded corners, will ignore..."); + ps->o.corner_radius = 0; + } + // window_stack shouldn't include window that's // not in the hash table at this point. Since // there cannot be any fading windows. @@ -1664,9 +1679,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .randr_exists = 0, .randr_event = 0, .randr_error = 0, +#ifdef CONFIG_OPENGL .glx_exists = false, .glx_event = 0, .glx_error = 0, +#endif .xrfilter_convolution_exists = false, .atoms_wintypes = {0}, @@ -1864,6 +1881,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, c2_list_postprocess(ps, ps->o.invert_color_list) && c2_list_postprocess(ps, ps->o.opacity_rules) && c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) && + c2_list_postprocess(ps, ps->o.round_borders_blacklist) && c2_list_postprocess(ps, ps->o.focus_blacklist))) { log_error("Post-processing of conditionals failed, some of your rules " "might not work"); @@ -2240,6 +2258,7 @@ static void session_destroy(session_t *ps) { free_wincondlst(&ps->o.paint_blacklist); free_wincondlst(&ps->o.unredir_if_possible_blacklist); free_wincondlst(&ps->o.rounded_corners_blacklist); + free_wincondlst(&ps->o.round_borders_blacklist); // Free tracked atom list { diff --git a/src/render.c b/src/render.c index 8fe6e87de7..4267cfeb1b 100644 --- a/src/render.c +++ b/src/render.c @@ -378,12 +378,14 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { * */ static inline void -win_round_corners(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx, - float cr, xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { +win_round_corners(session_t *ps, struct managed_win *w attr_unused, float cr attr_unused, + xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) { +#ifdef CONFIG_OPENGL const int16_t x = w->g.x; const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); const auto hei = to_u16_checked(w->heightb); +#endif //log_debug("x:%d y:%d w:%d h:%d", x, y, wid, hei); @@ -394,13 +396,8 @@ win_round_corners(session_t *ps, struct managed_win *w, const glx_texture_t *pte } break; #ifdef CONFIG_OPENGL case BKEND_GLX: - if (shader_idx == 1) { - glx_round_corners_dst1(ps, w, ptex, shader_idx, x, y, wid, hei, - (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); - } else { - glx_round_corners_dst0(ps, w, ptex, shader_idx, x, y, wid, hei, - (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); - } + glx_round_corners_dst(ps, w, w->glx_texture_bg, x, y, wid, hei, + (float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache); break; #endif default: assert(0); @@ -1109,6 +1106,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { if (pixman_region32_not_empty(®_tmp)) { set_tgt_clip(ps, ®_tmp); +#ifdef CONFIG_OPENGL // If rounded corners backup the region first if (w->corner_radius > 0) { const int16_t x = w->g.x; @@ -1117,6 +1115,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { const auto hei = to_u16_checked(w->heightb); glx_bind_texture(ps, &w->glx_texture_bg, x, y, wid, hei, false); } +#endif // Blur window background if (w->blur_background && @@ -1130,8 +1129,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { // Round window corners if (w->corner_radius > 0) { - win_round_corners(ps, w, w->glx_texture_bg, 0, - (float)w->corner_radius, ps->tgt_buffer.pict, ®_tmp); } + win_round_corners(ps, w, (float)w->corner_radius, + ps->tgt_buffer.pict, ®_tmp); + } } } diff --git a/src/win.c b/src/win.c index d9faa4ad35..7ca2f9cd42 100644 --- a/src/win.c +++ b/src/win.c @@ -913,6 +913,11 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) // we query the color in glx_round_corners_dst0 using glReadPixels //w->border_col = { -1., -1, -1, -1 }; w->border_col[0] = w->border_col[1] = w->border_col[2] = w->border_col[3] = -1.0; + if (w && c2_match(ps, w, ps->o.round_borders_blacklist, NULL)) { + w->round_borders = 0; + } else { + w->round_borders = ps->o.round_borders; + } } } diff --git a/src/win.h b/src/win.h index 4edd1a5ee8..5c13927ad1 100644 --- a/src/win.h +++ b/src/win.h @@ -204,6 +204,7 @@ struct managed_win { /// Corner radius int corner_radius; + bool round_borders; float border_col[4]; // Fading-related members From c5abd7ee9236803dcf39ffb02a9d990a1835c38a Mon Sep 17 00:00:00 2001 From: bhagwan Date: Tue, 5 May 2020 16:28:28 -0700 Subject: [PATCH 37/38] minor modifications for tests and no-opengl build --- src/opengl.c | 1 - src/picom.c | 2 ++ src/x.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/opengl.c b/src/opengl.c index 74e19eb187..b289df28f0 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -1249,7 +1249,6 @@ bool glx_round_corners_dst(session_t *ps, struct managed_win *w, const glx_textu int dx, int dy, int width, int height, float z, float cr, const region_t *reg_tgt attr_unused, glx_blur_cache_t *pbc attr_unused) { - assert(shader_idx >= 0 && shader_idx <= 1); assert(ps->psglx->round_passes[0].prog); assert(ps->psglx->round_passes[1].prog); bool ret = false; diff --git a/src/picom.c b/src/picom.c index 95ccbb6713..2137ddf816 100644 --- a/src/picom.c +++ b/src/picom.c @@ -1808,9 +1808,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id); if (ext_info && ext_info->present) { +#if CONFIG_OPENGL ps->glx_exists = true; ps->glx_error = ext_info->first_error; ps->glx_event = ext_info->first_event; +#endif } // Parse configuration file diff --git a/src/x.c b/src/x.c index b45e148c32..d75d0171b8 100644 --- a/src/x.c +++ b/src/x.c @@ -382,6 +382,7 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c CASESTRRET2(RENDER_GLYPH); } +#ifdef CONFIG_OPENGL if (ps->glx_exists) { o = error_code - ps->glx_error; switch (o) { @@ -401,6 +402,7 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c CASESTRRET2(GLX_GLX_BAD_PROFILE_ARB); } } +#endif if (ps->xsync_exists) { o = error_code - ps->xsync_error; From a99772b6d540194628800e0168d587cf1d62b097 Mon Sep 17 00:00:00 2001 From: bhagwan Date: Tue, 5 May 2020 16:31:23 -0700 Subject: [PATCH 38/38] last warning fix for tests to pass --- src/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render.c b/src/render.c index 4267cfeb1b..fc704998cf 100644 --- a/src/render.c +++ b/src/render.c @@ -245,7 +245,7 @@ uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ return n; } -void render(session_t *ps, struct managed_win *w, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, +void render(session_t *ps, struct managed_win *w attr_unused, int x, int y, int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity, bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip) { switch (ps->o.backend) {