Skip to content

Commit 79f96ad

Browse files
authored
Fix RoundedCornersEffect (#2655)
Third time's a charm Rename .vert shaders to .frag because well, these are fragment shaders, not vertex shaders. Fixes the strange offsets in shader code by correctly calculating offsets using clutter_actor_box_enlarge_for_effects which is mutter private api. This works with and without fractional scaling which was the flaw of my previous attempts
1 parent c29d651 commit 79f96ad

File tree

7 files changed

+109
-30
lines changed

7 files changed

+109
-30
lines changed

data/gala.gresource.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
<file alias="buttons/resize.svg" compressed="true" preprocess="xml-stripblanks">resize.svg</file>
2222
</gresource>
2323
<gresource prefix="/io/elementary/desktop/gala">
24-
<file compressed="true">shaders/colorblindness-correction.vert</file>
25-
<file compressed="true">shaders/monochrome.vert</file>
26-
<file compressed="true">shaders/rounded-corners.vert</file>
24+
<file compressed="true">shaders/colorblindness-correction.frag</file>
25+
<file compressed="true">shaders/monochrome.frag</file>
26+
<file compressed="true">shaders/rounded-corners.frag</file>
2727
</gresource>
2828
<gresource prefix="/io/elementary/desktop/gala-daemon">
2929
<file compressed="true">gala-daemon.css</file>
File renamed without changes.
Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,27 @@
66
// based on shader from mutter
77

88
uniform sampler2D tex;
9-
uniform float clip_radius;
9+
uniform int clip_radius;
1010
uniform vec2 actor_size;
11+
uniform vec2 offset;
12+
uniform vec2 full_texture_size;
1113

1214
float rounded_rect_coverage (vec2 p) {
13-
float center_left = clip_radius + 1.5;
14-
float center_right = actor_size.x - clip_radius - 0.55;
15-
float center_x;
15+
float center_left = clip_radius;
16+
float center_right = actor_size.x - clip_radius;
1617

18+
float center_x;
1719
if (p.x < center_left)
1820
center_x = center_left;
19-
else if (p.x >= center_right)
21+
else if (p.x > center_right)
2022
center_x = center_right;
2123
else
2224
return 1.0;
2325

24-
float center_top = clip_radius + 1.5;
25-
float center_bottom = actor_size.y - clip_radius - 0.55;
26-
float center_y;
26+
float center_top = clip_radius;
27+
float center_bottom = actor_size.y - clip_radius;
2728

29+
float center_y;
2830
if (p.y < center_top)
2931
center_y = center_top;
3032
else if (p.y > center_bottom)
@@ -42,18 +44,26 @@ float rounded_rect_coverage (vec2 p) {
4244

4345
// Fully inside the circle
4446
float inner_radius = clip_radius - 0.5;
45-
if (dist_squared <= (inner_radius * inner_radius))
47+
if (dist_squared < (inner_radius * inner_radius))
4648
return 1.0;
4749

4850
// Only pixels on the edge of the curve need expensive antialiasing
4951
return smoothstep (outer_radius, inner_radius, sqrt (dist_squared));
5052
}
5153

5254
void main () {
53-
vec4 sample = texture2D (tex, cogl_tex_coord0_in.xy);
55+
vec2 texture_coord = cogl_tex_coord0_in.xy * full_texture_size;
56+
if (texture_coord.x < offset.x || texture_coord.x > offset.x + actor_size.x ||
57+
texture_coord.y < offset.y || texture_coord.y > offset.y + actor_size.y
58+
) {
59+
cogl_color_out = vec4 (0, 0, 0, 0);
60+
return;
61+
}
5462

55-
vec2 texture_coord = cogl_tex_coord0_in.xy * actor_size;
56-
float res = rounded_rect_coverage (texture_coord);
63+
texture_coord.x -= offset.x;
64+
texture_coord.y -= offset.y;
5765

66+
vec4 sample = texture2D (tex, cogl_tex_coord0_in.xy);
67+
float res = rounded_rect_coverage (texture_coord);
5868
cogl_color_out = sample * cogl_color_in * res;
5969
}

lib/RoundedCornersEffect.vala

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
*/
55

66
public class Gala.RoundedCornersEffect : Clutter.ShaderEffect {
7-
private const int CLIP_RADIUS_OFFSET = 3;
8-
9-
public float clip_radius {
7+
private int _clip_radius;
8+
public int clip_radius {
9+
get {
10+
return _clip_radius;
11+
}
1012
construct set {
11-
set_uniform_value ("clip_radius", value + CLIP_RADIUS_OFFSET);
13+
_clip_radius = value;
14+
15+
if (actor != null) {
16+
update_clip_radius ();
17+
}
1218
}
1319
}
1420

@@ -21,12 +27,13 @@ public class Gala.RoundedCornersEffect : Clutter.ShaderEffect {
2127
_monitor_scale = value;
2228

2329
if (actor != null) {
30+
update_clip_radius ();
2431
update_actor_size ();
2532
}
2633
}
2734
}
2835

29-
public RoundedCornersEffect (float clip_radius, float monitor_scale) {
36+
public RoundedCornersEffect (int clip_radius, float monitor_scale) {
3037
Object (
3138
#if HAS_MUTTER48
3239
shader_type: Cogl.ShaderType.FRAGMENT,
@@ -38,13 +45,15 @@ public class Gala.RoundedCornersEffect : Clutter.ShaderEffect {
3845
);
3946
}
4047

41-
construct {
48+
public override string get_static_shader_source () {
4249
try {
43-
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/rounded-corners.vert", GLib.ResourceLookupFlags.NONE);
44-
set_shader_source ((string) bytes.get_data ());
50+
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/rounded-corners.frag", NONE);
51+
return (string) bytes.get_data ();
4552
} catch (Error e) {
46-
critical ("Unable to load rounded-corners.vert: %s", e.message);
53+
critical ("Unable to load rounded-corners.frag: %s", e.message);
4754
}
55+
56+
return "";
4857
}
4958

5059
public override void set_actor (Clutter.Actor? new_actor) {
@@ -59,18 +68,78 @@ public class Gala.RoundedCornersEffect : Clutter.ShaderEffect {
5968
actor.notify["width"].connect (update_actor_size);
6069
actor.notify["height"].connect (update_actor_size);
6170

71+
update_clip_radius ();
6272
update_actor_size ();
6373
}
6474
}
6575

76+
private void update_clip_radius () requires (actor != null) {
77+
set_uniform_value ("clip_radius", Utils.scale_to_int (clip_radius, monitor_scale));
78+
}
79+
6680
private void update_actor_size () requires (actor != null) {
81+
var actor_box = actor.get_allocation_box ();
82+
Clutter.ActorBox.clamp_to_pixel (ref actor_box);
83+
6784
float[] actor_size = {
68-
actor.width * monitor_scale,
69-
actor.height * monitor_scale
85+
Math.ceilf (actor_box.get_width ()),
86+
Math.ceilf (actor_box.get_height ())
7087
};
7188

7289
var actor_size_value = GLib.Value (typeof (Clutter.ShaderFloat));
7390
Clutter.Value.set_shader_float (actor_size_value, actor_size);
7491
set_uniform_value ("actor_size", actor_size_value);
92+
93+
var effect_box = actor_box.copy ();
94+
clutter_actor_box_enlarge_for_effects (ref effect_box);
95+
96+
float[] full_texture_size = {
97+
Math.ceilf (effect_box.get_width ()),
98+
Math.ceilf (effect_box.get_height ())
99+
};
100+
101+
var full_texture_size_value = GLib.Value (typeof (Clutter.ShaderFloat));
102+
Clutter.Value.set_shader_float (full_texture_size_value, full_texture_size);
103+
set_uniform_value ("full_texture_size", full_texture_size_value);
104+
105+
float[] offset = {
106+
Math.ceilf (actor_box.x1 - effect_box.x1),
107+
Math.ceilf (actor_box.y1 - effect_box.y1)
108+
};
109+
110+
var offset_value = GLib.Value (typeof (Clutter.ShaderFloat));
111+
Clutter.Value.set_shader_float (offset_value, offset);
112+
set_uniform_value ("offset", offset_value);
113+
}
114+
115+
/**
116+
* This is the same as mutter's private _clutter_actor_box_enlarge_for_effects function
117+
* Mutter basically enlarges the texture a bit to "determine a stable quantized size in pixels
118+
* that doesn't vary due to the original box's sub-pixel position."
119+
*
120+
* We need to account for this in our shader code so this function is reimplemented here.
121+
*/
122+
private void clutter_actor_box_enlarge_for_effects (ref Clutter.ActorBox box) {
123+
if (box.get_area () == 0.0) {
124+
return;
125+
}
126+
127+
var width = box.x2 - box.x1;
128+
var height = box.y2 - box.y1;
129+
width = nearbyint (width);
130+
height = nearbyint (height);
131+
132+
box.x2 = Math.ceilf (box.x2 + 0.75f);
133+
box.y2 = Math.ceilf (box.y2 + 0.75f);
134+
135+
box.x1 = box.x2 - width - 3;
136+
box.y1 = box.y2 - height - 3;
137+
}
138+
139+
/**
140+
* Mutter uses custom nearbyint macro instead of Math.nearbyintf
141+
*/
142+
private int nearbyint (float x) {
143+
return (int) ((x) < 0.0f ? (x) - 0.5f : (x) + 0.5f);
75144
}
76145
}

src/ColorFilters/ColorblindnessCorrectionEffect.vala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ public class Gala.ColorblindnessCorrectionEffect : Clutter.ShaderEffect {
4747
);
4848

4949
try {
50-
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/colorblindness-correction.vert", GLib.ResourceLookupFlags.NONE);
50+
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/colorblindness-correction.frag", GLib.ResourceLookupFlags.NONE);
5151
set_shader_source ((string) bytes.get_data ());
5252
} catch (Error e) {
53-
critical ("Unable to load colorblindness-correction.vert: %s", e.message);
53+
critical ("Unable to load colorblindness-correction.frag: %s", e.message);
5454
}
5555

5656
pause_for_screenshot = false;

src/ColorFilters/MonochromeEffect.vala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ public class Gala.MonochromeEffect : Clutter.ShaderEffect {
3838
);
3939

4040
try {
41-
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/monochrome.vert", GLib.ResourceLookupFlags.NONE);
41+
var bytes = GLib.resources_lookup_data ("/io/elementary/desktop/gala/shaders/monochrome.frag", GLib.ResourceLookupFlags.NONE);
4242
set_shader_source ((string) bytes.get_data ());
4343
} catch (Error e) {
44-
critical ("Unable to load monochrome.vert: %s", e.message);
44+
critical ("Unable to load monochrome.frag: %s", e.message);
4545
}
4646

4747
pause_for_screenshot = false;

0 commit comments

Comments
 (0)