From 1eafca9ba6662fb3e959f2fb9ebd3c10ae8bb87b Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:09:09 +0100 Subject: [PATCH 1/7] Fixed clipped region not being clipped with 0 corner radius --- types/scene/wlr_scene.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index a7f3c2f..ff5669b 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1615,7 +1615,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren }, }; - if (scene_rect->corner_radius && rect_corners != CORNER_LOCATION_NONE) { + if (!wlr_box_empty(&scene_rect->clipped_region.area) + || (scene_rect->corner_radius && rect_corners != CORNER_LOCATION_NONE)) { struct wlr_box clipped_region_box = scene_rect->clipped_region.area; int clipped_region_corner_radius = scene_rect->clipped_region.corner_radius; enum corner_location clipped_corners = scene_rect->clipped_region.corners; From 65787d16b2d609e33225660beafd75afe236fdb9 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:53:23 +0100 Subject: [PATCH 2/7] Made clip region positioning node-relative --- include/scenefx/types/wlr_scene.h | 4 ++++ types/scene/wlr_scene.c | 15 +++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/scenefx/types/wlr_scene.h b/include/scenefx/types/wlr_scene.h index c7c3ca8..3d055b7 100644 --- a/include/scenefx/types/wlr_scene.h +++ b/include/scenefx/types/wlr_scene.h @@ -430,6 +430,8 @@ void wlr_scene_rect_set_corner_radius(struct wlr_scene_rect *rect, int corner_ra * * For there to be corner rounding of the clipped region, the corner radius and * corners must be non-zero. + * + * NOTE: The positioning is node-relative. */ void wlr_scene_rect_set_clipped_region(struct wlr_scene_rect *rect, struct clipped_region clipped_region); @@ -483,6 +485,8 @@ void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float col * * For there to be corner rounding of the clipped region, the corner radius and * corners must be non-zero. + * + * NOTE: The positioning is node-relative. */ void wlr_scene_shadow_set_clipped_region(struct wlr_scene_shadow *shadow, struct clipped_region clipped_region); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index ff5669b..39d29e4 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1624,9 +1624,10 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren // Compensation int node_x, node_y; wlr_scene_node_coords(node, &node_x, &node_y); - clipped_region_box.x += node_x - node->x; - clipped_region_box.y += node_y - node->y; - + // Node relative -> Root relative + clipped_region_box.x += node_x; + clipped_region_box.y += node_y; + // Output relative clipped_region_box.x -= data->logical.x; clipped_region_box.y -= data->logical.y; @@ -1685,11 +1686,13 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren // Compensation int node_x, node_y; wlr_scene_node_coords(node, &node_x, &node_y); - clipped_region_box.x += node_x - node->x; - clipped_region_box.y += node_y - node->y; - + // Node relative -> Root relative + clipped_region_box.x += node_x; + clipped_region_box.y += node_y; + // Output relative clipped_region_box.x -= data->logical.x; clipped_region_box.y -= data->logical.y; + scale_box(&clipped_region_box, data->scale); transform_output_box(&clipped_region_box, data); corner_location_transform(node_transform, &clipped_corners); From 288e851936b275e81eaff0573e17bda29ff6998d Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:00:58 +0100 Subject: [PATCH 3/7] Added clipped region to the red rect in tinywl --- tinywl/tinywl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index 07207d3..a8af24e 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -1152,6 +1152,16 @@ int main(int argc, char *argv[]) { float top_rect_color[4] = { 1, 0, 0, 1 }; struct wlr_scene_rect *rect = wlr_scene_rect_create(server.layers.toplevel_layer, 200, 200, top_rect_color); + wlr_scene_rect_set_clipped_region(rect, (struct clipped_region) { + .corner_radius = 12, + .corners = CORNER_LOCATION_TOP, + .area = { + .x = 50, + .y = 50, + .width = 100, + .height = 100, + }, + }); wlr_scene_node_set_position(&rect->node, 200, 200); // blur From 80335d7ce2847cc2f64abc33b7ca179fe4c15b3c Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 29 Jan 2025 18:53:46 +0100 Subject: [PATCH 4/7] simplified node relative to root relative conversion --- types/scene/wlr_scene.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 39d29e4..6176164 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1621,15 +1621,9 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren int clipped_region_corner_radius = scene_rect->clipped_region.corner_radius; enum corner_location clipped_corners = scene_rect->clipped_region.corners; - // Compensation - int node_x, node_y; - wlr_scene_node_coords(node, &node_x, &node_y); // Node relative -> Root relative - clipped_region_box.x += node_x; - clipped_region_box.y += node_y; - // Output relative - clipped_region_box.x -= data->logical.x; - clipped_region_box.y -= data->logical.y; + clipped_region_box.x += x; + clipped_region_box.y += y; scale_box(&clipped_region_box, data->scale); transform_output_box(&clipped_region_box, data); @@ -1683,15 +1677,9 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren int clipped_region_corner_radius = scene_shadow->clipped_region.corner_radius; enum corner_location clipped_corners = scene_shadow->clipped_region.corners; - // Compensation - int node_x, node_y; - wlr_scene_node_coords(node, &node_x, &node_y); // Node relative -> Root relative - clipped_region_box.x += node_x; - clipped_region_box.y += node_y; - // Output relative - clipped_region_box.x -= data->logical.x; - clipped_region_box.y -= data->logical.y; + clipped_region_box.x += x; + clipped_region_box.y += y; scale_box(&clipped_region_box, data->scale); transform_output_box(&clipped_region_box, data); From c713a1b2a23be136580ca32a0b507853b6d313bd Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Tue, 4 Feb 2025 00:03:53 -0500 Subject: [PATCH 5/7] added clipping to rects --- include/render/fx_renderer/shaders.h | 8 +++ include/scenefx/render/pass.h | 3 +- render/fx_renderer/fx_pass.c | 53 +++++++++++++++++-- render/fx_renderer/gles2/shaders/quad.frag | 24 ++++++++- render/fx_renderer/shaders.c | 13 ++++- types/scene/wlr_scene.c | 60 +++++++++++----------- 6 files changed, 121 insertions(+), 40 deletions(-) diff --git a/include/render/fx_renderer/shaders.h b/include/render/fx_renderer/shaders.h index 883d360..9ed5a87 100644 --- a/include/render/fx_renderer/shaders.h +++ b/include/render/fx_renderer/shaders.h @@ -25,6 +25,14 @@ struct quad_shader { GLint proj; GLint color; GLint pos_attrib; + + GLint clip_size; + GLint clip_position; + GLint clip_corner_radius; + GLint clip_round_top_left; + GLint clip_round_top_right; + GLint clip_round_bottom_left; + GLint clip_round_bottom_right; }; bool link_quad_program(struct quad_shader *shader); diff --git a/include/scenefx/render/pass.h b/include/scenefx/render/pass.h index 48fb1dc..affa69d 100644 --- a/include/scenefx/render/pass.h +++ b/include/scenefx/render/pass.h @@ -60,7 +60,7 @@ struct fx_render_texture_options { struct fx_render_rect_options { struct wlr_render_rect_options base; - // TODO: Add effects here in the future + struct clipped_region clipped_region; }; struct fx_render_rect_grad_options { @@ -72,7 +72,6 @@ struct fx_render_rounded_rect_options { struct wlr_render_rect_options base; int corner_radius; enum corner_location corners; - struct clipped_region clipped_region; }; diff --git a/render/fx_renderer/fx_pass.c b/render/fx_renderer/fx_pass.c index fddafc9..f6d9146 100644 --- a/render/fx_renderer/fx_pass.c +++ b/render/fx_renderer/fx_pass.c @@ -37,6 +37,11 @@ struct fx_render_rect_options fx_render_rect_options_default( const struct wlr_render_rect_options *base) { struct fx_render_rect_options options = { .base = *base, + .clipped_region = { + .area = { .0, .0, .0, .0 }, + .corner_radius = 0, + .corners = CORNER_LOCATION_NONE, + }, }; return options; } @@ -345,13 +350,51 @@ void fx_render_pass_add_rect(struct fx_gles_render_pass *pass, struct wlr_box box; wlr_render_rect_options_get_box(options, pass->buffer->buffer, &box); - push_fx_debug(renderer); - setup_blending(color->a == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode); + pixman_region32_t clip_region; + if (options->clip) { + pixman_region32_init(&clip_region); + pixman_region32_copy(&clip_region, options->clip); + } else { + pixman_region32_init_rect(&clip_region, box.x, box.y, box.width, box.height); + } + const struct wlr_box clipped_region_box = fx_options->clipped_region.area; + enum corner_location clipped_region_corners = fx_options->clipped_region.corners; + int clipped_region_corner_radius = clipped_region_corners != CORNER_LOCATION_NONE ? + fx_options->clipped_region.corner_radius : 0; + if (!wlr_box_empty(&clipped_region_box)) { + pixman_region32_t user_clip_region; + pixman_region32_init_rect( + &user_clip_region, + clipped_region_box.x + clipped_region_corner_radius * 0.3, + clipped_region_box.y + clipped_region_corner_radius * 0.3, + fmax(clipped_region_box.width - clipped_region_corner_radius * 0.6, 0), + fmax(clipped_region_box.height - clipped_region_corner_radius * 0.6, 0) + ); + pixman_region32_subtract(&clip_region, &clip_region, &user_clip_region); + pixman_region32_fini(&user_clip_region); - glUseProgram(renderer->shaders.quad.program); + push_fx_debug(renderer); + setup_blending(options->blend_mode); + } else { + push_fx_debug(renderer); + setup_blending(color->a == 1.0 ? WLR_RENDER_BLEND_MODE_NONE : options->blend_mode); + } - set_proj_matrix(renderer->shaders.quad.proj, pass->projection_matrix, &box); - glUniform4f(renderer->shaders.quad.color, color->r, color->g, color->b, color->a); + struct quad_shader shader = renderer->shaders.quad; + glUseProgram(shader.program); + set_proj_matrix(shader.proj, pass->projection_matrix, &box); + glUniform4f(shader.color, color->r, color->g, color->b, color->a); + glUniform2f(shader.clip_size, clipped_region_box.width, clipped_region_box.height); + glUniform2f(shader.clip_position, clipped_region_box.x, clipped_region_box.y); + glUniform1f(shader.clip_corner_radius, fx_options->clipped_region.corner_radius); + glUniform1f(shader.clip_round_top_left, + (CORNER_LOCATION_TOP_LEFT & clipped_region_corners) == CORNER_LOCATION_TOP_LEFT); + glUniform1f(shader.clip_round_top_right, + (CORNER_LOCATION_TOP_RIGHT & clipped_region_corners) == CORNER_LOCATION_TOP_RIGHT); + glUniform1f(shader.clip_round_bottom_left, + (CORNER_LOCATION_BOTTOM_LEFT & clipped_region_corners) == CORNER_LOCATION_BOTTOM_LEFT); + glUniform1f(shader.clip_round_bottom_right, + (CORNER_LOCATION_BOTTOM_RIGHT & clipped_region_corners) == CORNER_LOCATION_BOTTOM_RIGHT); render(&box, options->clip, renderer->shaders.quad.pos_attrib); diff --git a/render/fx_renderer/gles2/shaders/quad.frag b/render/fx_renderer/gles2/shaders/quad.frag index 97d3a31..0dd7ce6 100644 --- a/render/fx_renderer/gles2/shaders/quad.frag +++ b/render/fx_renderer/gles2/shaders/quad.frag @@ -6,8 +6,28 @@ precision mediump float; varying vec4 v_color; varying vec2 v_texcoord; -uniform vec4 color; + +uniform vec2 clip_size; +uniform vec2 clip_position; +uniform float clip_corner_radius; +uniform bool clip_round_top_left; +uniform bool clip_round_top_right; +uniform bool clip_round_bottom_left; +uniform bool clip_round_bottom_right; + +float corner_alpha(vec2 size, vec2 position, float radius, + bool round_tl, bool round_tr, bool round_bl, bool round_br); void main() { - gl_FragColor = color; + // Clipping + float clip_corner_alpha = corner_alpha(clip_size, clip_position, clip_corner_radius, + clip_round_top_left, clip_round_top_right, + clip_round_bottom_left, clip_round_bottom_right); + + float base_case = float(clip_round_top_left) + float(clip_round_top_right) + + float(clip_round_bottom_left) + float(clip_round_bottom_right); + base_case *= step(1.0, clip_corner_radius); // Corner radius is 0 + clip_corner_alpha = max(clip_corner_alpha, 1.0 - step(1.0, base_case)); + + gl_FragColor = v_color * clip_corner_alpha; } diff --git a/render/fx_renderer/shaders.c b/render/fx_renderer/shaders.c index 6807592..cd5c389 100644 --- a/render/fx_renderer/shaders.c +++ b/render/fx_renderer/shaders.c @@ -104,8 +104,12 @@ void load_gl_proc(void *proc_ptr, const char *name) { // Shaders bool link_quad_program(struct quad_shader *shader) { + GLchar quad_src[4096]; + snprintf(quad_src, sizeof(quad_src), "%s\n%s", quad_frag_src, + corner_alpha_frag_src); + GLuint prog; - shader->program = prog = link_program(quad_frag_src); + shader->program = prog = link_program(quad_src); if (!shader->program) { return false; } @@ -113,6 +117,13 @@ bool link_quad_program(struct quad_shader *shader) { shader->proj = glGetUniformLocation(prog, "proj"); shader->color = glGetUniformLocation(prog, "color"); shader->pos_attrib = glGetAttribLocation(prog, "pos"); + shader->clip_size = glGetUniformLocation(prog, "clip_size"); + shader->clip_position = glGetUniformLocation(prog, "clip_position"); + shader->clip_corner_radius = glGetUniformLocation(prog, "clip_corner_radius"); + shader->clip_round_top_left = glGetUniformLocation(prog, "clip_round_top_left"); + shader->clip_round_top_right = glGetUniformLocation(prog, "clip_round_top_right"); + shader->clip_round_bottom_left = glGetUniformLocation(prog, "clip_round_bottom_left"); + shader->clip_round_bottom_right = glGetUniformLocation(prog, "clip_round_bottom_right"); return true; } diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 6176164..a300792 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -1602,6 +1602,18 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren pixman_region32_fini(&opaque_region); } + struct wlr_box rect_clipped_region_box = scene_rect->clipped_region.area; + int rect_clipped_region_corner_radius = scene_rect->clipped_region.corner_radius; + enum corner_location rect_clipped_corners = scene_rect->clipped_region.corners; + + // Node relative -> Root relative + rect_clipped_region_box.x += x; + rect_clipped_region_box.y += y; + + scale_box(&rect_clipped_region_box, data->scale); + transform_output_box(&rect_clipped_region_box, data); + corner_location_transform(node_transform, &rect_clipped_corners); + struct fx_render_rect_options rect_options = { .base = { .box = dst_box, @@ -1613,31 +1625,19 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren }, .clip = &render_region, }, + .clipped_region = { + .area = rect_clipped_region_box, + .corner_radius = rect_clipped_region_corner_radius * data->scale, + .corners = rect_clipped_corners, + }, }; - if (!wlr_box_empty(&scene_rect->clipped_region.area) - || (scene_rect->corner_radius && rect_corners != CORNER_LOCATION_NONE)) { - struct wlr_box clipped_region_box = scene_rect->clipped_region.area; - int clipped_region_corner_radius = scene_rect->clipped_region.corner_radius; - enum corner_location clipped_corners = scene_rect->clipped_region.corners; - - // Node relative -> Root relative - clipped_region_box.x += x; - clipped_region_box.y += y; - - scale_box(&clipped_region_box, data->scale); - transform_output_box(&clipped_region_box, data); - corner_location_transform(node_transform, &clipped_corners); - + if (scene_rect->corner_radius && rect_corners != CORNER_LOCATION_NONE) { struct fx_render_rounded_rect_options rounded_rect_options = { .base = rect_options.base, .corner_radius = scene_rect->corner_radius * data->scale, .corners = rect_corners, - .clipped_region = { - .area = clipped_region_box, - .corner_radius = clipped_region_corner_radius * data->scale, - .corners = clipped_corners, - }, + .clipped_region = rect_options.clipped_region, }; fx_render_pass_add_rounded_rect(data->render_pass, &rounded_rect_options); } else { @@ -1673,24 +1673,24 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren case WLR_SCENE_NODE_SHADOW:; struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node); - struct wlr_box clipped_region_box = scene_shadow->clipped_region.area; - int clipped_region_corner_radius = scene_shadow->clipped_region.corner_radius; - enum corner_location clipped_corners = scene_shadow->clipped_region.corners; + struct wlr_box shadow_clipped_region_box = scene_shadow->clipped_region.area; + int shadow_clipped_region_corner_radius = scene_shadow->clipped_region.corner_radius; + enum corner_location shadow_clipped_corners = scene_shadow->clipped_region.corners; // Node relative -> Root relative - clipped_region_box.x += x; - clipped_region_box.y += y; + shadow_clipped_region_box.x += x; + shadow_clipped_region_box.y += y; - scale_box(&clipped_region_box, data->scale); - transform_output_box(&clipped_region_box, data); - corner_location_transform(node_transform, &clipped_corners); + scale_box(&shadow_clipped_region_box, data->scale); + transform_output_box(&shadow_clipped_region_box, data); + corner_location_transform(node_transform, &shadow_clipped_corners); struct fx_render_box_shadow_options shadow_options = { .box = dst_box, .clipped_region = { - .area = clipped_region_box, - .corner_radius = clipped_region_corner_radius * data->scale, - .corners = clipped_corners, + .area = shadow_clipped_region_box, + .corner_radius = shadow_clipped_region_corner_radius * data->scale, + .corners = shadow_clipped_corners, }, .blur_sigma = scene_shadow->blur_sigma, .corner_radius = scene_shadow->corner_radius * data->scale, From c1c8c53eb4518e2e8e16c6b3d130164929937c26 Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Tue, 4 Feb 2025 00:13:58 -0500 Subject: [PATCH 6/7] fixed border and shadow clipped region placement in tinywl --- tinywl/tinywl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index a8af24e..e22cf49 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -612,7 +612,7 @@ static void xdg_toplevel_commit(struct wl_listener *listener, void *data) { wlr_scene_rect_set_clipped_region(toplevel->border, (struct clipped_region) { .corner_radius = toplevel->corner_radius, .corners = CORNER_LOCATION_ALL, - .area = { 0, 0, geometry.width, geometry.height } + .area = { BORDER_THICKNESS, BORDER_THICKNESS, geometry.width, geometry.height } }); int blur_sigma = toplevel->shadow->blur_sigma; @@ -622,7 +622,7 @@ static void xdg_toplevel_commit(struct wl_listener *listener, void *data) { wlr_scene_shadow_set_clipped_region(toplevel->shadow, (struct clipped_region) { .corner_radius = toplevel->corner_radius + BORDER_THICKNESS, .corners = CORNER_LOCATION_ALL, - .area = { -BORDER_THICKNESS, -BORDER_THICKNESS, border_width, border_height } + .area = { blur_sigma, blur_sigma, border_width, border_height } }); } From 17f09e365d042208bb02cb2c021018f45cfec035 Mon Sep 17 00:00:00 2001 From: William McKinnon Date: Tue, 4 Feb 2025 00:18:17 -0500 Subject: [PATCH 7/7] only round bottom corners --- tinywl/tinywl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index e22cf49..69d6789 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -970,7 +970,7 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) { toplevel->border = wlr_scene_rect_create(toplevel->scene_tree, 0, 0, (float[4]){ 1.0f, 0.f, 0.f, 1.0f }); wlr_scene_rect_set_corner_radius(toplevel->border, - toplevel->corner_radius + BORDER_THICKNESS, CORNER_LOCATION_ALL); + toplevel->corner_radius + BORDER_THICKNESS, CORNER_LOCATION_BOTTOM); wlr_scene_node_set_position(&toplevel->border->node, -BORDER_THICKNESS, -BORDER_THICKNESS); float blur_sigma = 20.0f;