🔒 Repository is read-only – file editing is disabled.

recipes/gui/wlroots/wlroots-0.20.2-rounded-clip.patch main

368 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
diff -ruN a/include/render/gles2.h b/include/render/gles2.h
--- a/include/render/gles2.h	2026-07-07 23:46:09.000000000 +0200
+++ b/include/render/gles2.h	2026-08-31 12:49:04.008068765 +0200
@@ -35,6 +35,12 @@
 	GLint tex;
 	GLint alpha;
 	GLint pos_attrib;
+	/* PaganDE: rounded clip */
+	GLint rounded;
+	GLint box_pos;
+	GLint box_size;
+	GLint radius;
+	GLint corners;
 };
 
 struct wlr_gles2_renderer {
diff -ruN a/include/wlr/render/pass.h b/include/wlr/render/pass.h
--- a/include/wlr/render/pass.h	2026-07-07 23:46:09.000000000 +0200
+++ b/include/wlr/render/pass.h	2026-08-31 12:49:04.007446160 +0200
@@ -84,6 +84,14 @@
 	WLR_SCALE_FILTER_NEAREST,
 };
 
+/* PaganDE: rounded corners bitmask (see corner_radius below) */
+enum wlr_rounded_corner {
+	WLR_ROUNDED_CORNER_TOP_LEFT = 1 << 0,
+	WLR_ROUNDED_CORNER_TOP_RIGHT = 1 << 1,
+	WLR_ROUNDED_CORNER_BOTTOM_RIGHT = 1 << 2,
+	WLR_ROUNDED_CORNER_BOTTOM_LEFT = 1 << 3,
+};
+
 struct wlr_render_texture_options {
 	/* Source texture */
 	struct wlr_texture *texture;
@@ -95,6 +103,12 @@
 	const float *alpha;
 	/* Clip region, leave NULL to disable clipping */
 	const pixman_region32_t *clip;
+	/* PaganDE: rounded corners. When corner_radius > 0 and rounded_corners != 0,
+	 * the texture is clipped to a rectangle with rounded corners (bitmask of
+	 * enum wlr_rounded_corner). Renderers that do not support this feature
+	 * must ignore these fields. */
+	float corner_radius;
+	uint32_t rounded_corners;
 	/* Transform applied to the source texture */
 	enum wl_output_transform transform;
 	/* Filtering */
diff -ruN a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
--- a/include/wlr/types/wlr_scene.h	2026-07-07 23:46:09.000000000 +0200
+++ b/include/wlr/types/wlr_scene.h	2026-08-31 12:49:04.007705726 +0200
@@ -215,6 +215,11 @@
 
 		// True if the underlying buffer is a wlr_single_pixel_buffer_v1
 		bool is_single_pixel_buffer;
+
+		// PaganDE: rounded clip applied when rendering this buffer
+		// (see wlr_scene_buffer_set_rounded_clip)
+		float clip_radius;
+		uint32_t clip_corners;
 		// If is_single_pixel_buffer is set, contains the color of the buffer
 		// as {R, G, B, A} where the max value of each component is UINT32_MAX
 		uint32_t single_pixel_buffer_color[4];
@@ -549,6 +554,16 @@
 	enum wl_output_transform transform);
 
 /**
+ * PaganDE: clip the buffer to a rectangle with rounded corners.
+ *
+ * radius is the corner radius in output pixels; corners is a bitmask of
+ * enum wlr_rounded_corner. Passing radius 0 (or corners 0) disables the clip.
+ * Renderers without support (e.g. pixman) ignore this.
+ */
+void wlr_scene_buffer_set_rounded_clip(struct wlr_scene_buffer *scene_buffer,
+	float radius, uint32_t corners);
+
+/**
 * Sets the opacity of this buffer
 */
 void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
diff -ruN a/render/gles2/pass.c b/render/gles2/pass.c
--- a/render/gles2/pass.c	2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/pass.c	2026-08-31 12:53:51.197412809 +0200
@@ -247,6 +247,19 @@
 	set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box);
 	set_tex_matrix(shader->tex_proj, options->transform, &src_fbox);
 
+	bool rounded = options->corner_radius > 0 && options->rounded_corners != 0;
+	glUniform1f(shader->rounded, rounded ? 1.0f : 0.0f);
+	if (rounded) {
+		glUniform2f(shader->box_pos, dst_box.x, dst_box.y);
+		glUniform2f(shader->box_size, dst_box.width, dst_box.height);
+		glUniform1f(shader->radius, options->corner_radius);
+		glUniform4f(shader->corners,
+			(options->rounded_corners & WLR_ROUNDED_CORNER_TOP_LEFT) ? 1.0f : 0.0f,
+			(options->rounded_corners & WLR_ROUNDED_CORNER_TOP_RIGHT) ? 1.0f : 0.0f,
+			(options->rounded_corners & WLR_ROUNDED_CORNER_BOTTOM_RIGHT) ? 1.0f : 0.0f,
+			(options->rounded_corners & WLR_ROUNDED_CORNER_BOTTOM_LEFT) ? 1.0f : 0.0f);
+	}
+
 	render(&dst_box, options->clip, shader->pos_attrib);
 
 	glBindTexture(texture->target, 0);
diff -ruN a/render/gles2/renderer.c b/render/gles2/renderer.c
--- a/render/gles2/renderer.c	2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/renderer.c	2026-08-31 12:49:04.008364833 +0200
@@ -652,6 +652,11 @@
 	renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex");
 	renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha");
 	renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos");
+	renderer->shaders.tex_rgba.rounded = glGetUniformLocation(prog, "u_rounded");
+	renderer->shaders.tex_rgba.box_pos = glGetUniformLocation(prog, "u_box_pos");
+	renderer->shaders.tex_rgba.box_size = glGetUniformLocation(prog, "u_box_size");
+	renderer->shaders.tex_rgba.radius = glGetUniformLocation(prog, "u_radius");
+	renderer->shaders.tex_rgba.corners = glGetUniformLocation(prog, "u_corners");
 
 	renderer->shaders.tex_rgbx.program = prog =
 		link_program(renderer, common_vert_src, tex_rgbx_frag_src);
@@ -663,6 +668,11 @@
 	renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex");
 	renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha");
 	renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos");
+	renderer->shaders.tex_rgbx.rounded = glGetUniformLocation(prog, "u_rounded");
+	renderer->shaders.tex_rgbx.box_pos = glGetUniformLocation(prog, "u_box_pos");
+	renderer->shaders.tex_rgbx.box_size = glGetUniformLocation(prog, "u_box_size");
+	renderer->shaders.tex_rgbx.radius = glGetUniformLocation(prog, "u_radius");
+	renderer->shaders.tex_rgbx.corners = glGetUniformLocation(prog, "u_corners");
 
 	if (renderer->exts.OES_egl_image_external) {
 		renderer->shaders.tex_ext.program = prog =
@@ -675,6 +685,11 @@
 		renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex");
 		renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha");
 		renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos");
+	renderer->shaders.tex_ext.rounded = glGetUniformLocation(prog, "u_rounded");
+	renderer->shaders.tex_ext.box_pos = glGetUniformLocation(prog, "u_box_pos");
+	renderer->shaders.tex_ext.box_size = glGetUniformLocation(prog, "u_box_size");
+	renderer->shaders.tex_ext.radius = glGetUniformLocation(prog, "u_radius");
+	renderer->shaders.tex_ext.corners = glGetUniformLocation(prog, "u_corners");
 	}
 
 	pop_gles2_debug(renderer);
diff -ruN a/render/gles2/shaders/tex_external.frag b/render/gles2/shaders/tex_external.frag
--- a/render/gles2/shaders/tex_external.frag	2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/shaders/tex_external.frag	2026-08-31 12:53:34.209558298 +0200
@@ -10,6 +10,51 @@
 uniform samplerExternalOES texture0;
 uniform float alpha;
 
+
+// PaganDE: rounded clip (discard fragments outside the rounded rect)
+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
+uniform float u_rounded;
+uniform vec2 u_box_pos;
+uniform vec2 u_box_size;
+uniform float u_radius;
+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
+
+void rounded_clip() {
+	if (u_rounded == 0.0) {
+		return;
+	}
+	vec2 p = gl_FragCoord.xy - u_box_pos;
+	float r = u_radius;
+	/* top-left */
+	if (u_corners.x > 0.5) {
+		if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
+			discard;
+		}
+	}
+	/* top-right */
+	if (u_corners.y > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y <= r
+				&& distance(p, vec2(u_box_size.x - r, r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-right */
+	if (u_corners.z > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-left */
+	if (u_corners.w > 0.5) {
+		if (p.x <= r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+}
+
 void main() {
+	rounded_clip();
 	gl_FragColor = texture2D(texture0, v_texcoord) * alpha;
 }
diff -ruN a/render/gles2/shaders/tex_rgba.frag b/render/gles2/shaders/tex_rgba.frag
--- a/render/gles2/shaders/tex_rgba.frag	2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/shaders/tex_rgba.frag	2026-08-31 12:53:34.209518897 +0200
@@ -8,6 +8,51 @@
 uniform sampler2D tex;
 uniform float alpha;
 
+
+// PaganDE: rounded clip (discard fragments outside the rounded rect)
+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
+uniform float u_rounded;
+uniform vec2 u_box_pos;
+uniform vec2 u_box_size;
+uniform float u_radius;
+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
+
+void rounded_clip() {
+	if (u_rounded == 0.0) {
+		return;
+	}
+	vec2 p = gl_FragCoord.xy - u_box_pos;
+	float r = u_radius;
+	/* top-left */
+	if (u_corners.x > 0.5) {
+		if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
+			discard;
+		}
+	}
+	/* top-right */
+	if (u_corners.y > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y <= r
+				&& distance(p, vec2(u_box_size.x - r, r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-right */
+	if (u_corners.z > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-left */
+	if (u_corners.w > 0.5) {
+		if (p.x <= r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+}
+
 void main() {
+	rounded_clip();
 	gl_FragColor = texture2D(tex, v_texcoord) * alpha;
 }
diff -ruN a/render/gles2/shaders/tex_rgbx.frag b/render/gles2/shaders/tex_rgbx.frag
--- a/render/gles2/shaders/tex_rgbx.frag	2026-07-07 23:46:09.000000000 +0200
+++ b/render/gles2/shaders/tex_rgbx.frag	2026-08-31 12:53:34.209462266 +0200
@@ -8,6 +8,51 @@
 uniform sampler2D tex;
 uniform float alpha;
 
+
+// PaganDE: rounded clip (discard fragments outside the rounded rect)
+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
+uniform float u_rounded;
+uniform vec2 u_box_pos;
+uniform vec2 u_box_size;
+uniform float u_radius;
+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
+
+void rounded_clip() {
+	if (u_rounded == 0.0) {
+		return;
+	}
+	vec2 p = gl_FragCoord.xy - u_box_pos;
+	float r = u_radius;
+	/* top-left */
+	if (u_corners.x > 0.5) {
+		if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
+			discard;
+		}
+	}
+	/* top-right */
+	if (u_corners.y > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y <= r
+				&& distance(p, vec2(u_box_size.x - r, r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-right */
+	if (u_corners.z > 0.5) {
+		if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+	/* bottom-left */
+	if (u_corners.w > 0.5) {
+		if (p.x <= r && p.y >= u_box_size.y - r
+				&& distance(p, vec2(r, u_box_size.y - r)) > r) {
+			discard;
+		}
+	}
+}
+
 void main() {
+	rounded_clip();
 	gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
 }
diff -ruN a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
--- a/types/scene/wlr_scene.c	2026-07-07 23:46:09.000000000 +0200
+++ b/types/scene/wlr_scene.c	2026-08-31 12:49:04.007960213 +0200
@@ -1124,6 +1124,18 @@
 	}
 }
 
+void wlr_scene_buffer_set_rounded_clip(struct wlr_scene_buffer *scene_buffer,
+		float radius, uint32_t corners) {
+	if (scene_buffer->clip_radius == radius
+			&& scene_buffer->clip_corners == corners) {
+		return;
+	}
+	assert(radius >= 0);
+	scene_buffer->clip_radius = radius;
+	scene_buffer->clip_corners = corners;
+	scene_node_update(&scene_buffer->node, NULL);
+}
+
 void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
 		float opacity) {
 	if (scene_buffer->opacity == opacity) {
@@ -1499,6 +1511,26 @@
 	case WLR_SCENE_NODE_BUFFER:;
 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 
+		bool rounded = scene_buffer->clip_radius > 0
+			&& scene_buffer->clip_corners != 0;
+		if (rounded) {
+			/* Corner areas are no longer opaque: exclude them from the
+			 * opaque region so occlusion and blending stay correct. */
+			int r = (int)scene_buffer->clip_radius;
+			pixman_region32_t corners;
+			pixman_region32_init(&corners);
+			pixman_region32_union_rect(&corners, &corners,
+				x, y, r, r);
+			pixman_region32_union_rect(&corners, &corners,
+				x + dst_box.width - r, y, r, r);
+			pixman_region32_union_rect(&corners, &corners,
+				x + dst_box.width - r, y + dst_box.height - r, r, r);
+			pixman_region32_union_rect(&corners, &corners,
+				x, y + dst_box.height - r, r, r);
+			pixman_region32_subtract(&opaque, &opaque, &corners);
+			pixman_region32_fini(&corners);
+		}
+
 		if (scene_buffer->is_single_pixel_buffer) {
 			// Render the buffer as a rect, this is likely to be more efficient
 			wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
@@ -1544,9 +1576,11 @@
 			.dst_box = dst_box,
 			.transform = transform,
 			.clip = &render_region,
+			.corner_radius = scene_buffer->clip_radius,
+			.rounded_corners = scene_buffer->clip_corners,
 			.alpha = &scene_buffer->opacity,
 			.filter_mode = scene_buffer->filter_mode,
-			.blend_mode = !data->output->scene->calculate_visibility ||
+			.blend_mode = rounded || !data->output->scene->calculate_visibility ||
 					!pixman_region32_empty(&opaque) ?
 				WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
 			.transfer_function = scene_buffer->transfer_function,