Skip to content

Commit 1d810ea

Browse files
author
Jeronimo Garcia
committed
fix: add dispose() methods and scale body images to prevent VRAM/GTT memory leaks
Add proper resource cleanup in dispose() methods for several widget classes and scale body images to display size to prevent GPU memory (VRAM/GTT) leaks. Changes: - Notification: Add dispose() to clear img, img_app_icon, body_image and remove pending timeouts. Also clear body_image before setting new paintable. - Notification: Scale body images to display size instead of loading full resolution (e.g., 2560x1440 screenshots were using ~11MB GPU memory each, now use ~120KB when scaled to 200x100 display size). - MprisPlayer: Add dispose() and enhance before_destroy() to cancel downloads and clear album_art/background_picture textures. Clear textures before loading new album art. - Underlay: Add dispose() to properly unparent children. - NotificationGroup: Add dispose() to skip/null animations and clear collections. These fixes address GPU memory accumulation observed when: - Notifications with large images (screenshots) are shown - MPRIS players update album art frequently - Notification groups are expanded/collapsed The body image scaling fix provides ~100x reduction in GPU memory per image notification containing large images like screenshots.
1 parent 2083415 commit 1d810ea

4 files changed

Lines changed: 138 additions & 2 deletions

File tree

src/controlCenter/widgets/mpris/mpris_player.vala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,20 @@ namespace SwayNotificationCenter.Widgets.Mpris {
9898
album_art.set_visible (mpris_config.show_album_art == AlbumArtState.ALWAYS);
9999
}
100100

101+
public override void dispose () {
102+
before_destroy ();
103+
base.dispose ();
104+
}
105+
101106
public void before_destroy () {
102107
source.properties_changed.disconnect (properties_changed);
108+
109+
// Cancel any ongoing album art download
110+
album_art_cancellable.cancel ();
111+
112+
// Clear album art textures to release VRAM/GPU memory
113+
album_art.clear ();
114+
background_picture.set_paintable (null);
103115
}
104116

105117
private void properties_changed (string iface,
@@ -263,6 +275,10 @@ namespace SwayNotificationCenter.Widgets.Mpris {
263275
// Cancel previous download, reset the state and download again
264276
album_art_cancellable.cancel ();
265277
album_art_cancellable.reset ();
278+
279+
// Clear previous textures before loading new ones to release GPU memory
280+
album_art.clear ();
281+
background_picture.set_paintable (null);
266282

267283
Gdk.Texture ?album_art_texture = null;
268284
try {

src/notification/notification.vala

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ namespace SwayNotificationCenter {
105105

106106
private Notification () {}
107107

108+
public override void dispose () {
109+
// Clear all image resources to release VRAM/GPU memory
110+
img.clear ();
111+
img_app_icon.clear ();
112+
body_image.set_paintable (null);
113+
114+
// Remove any pending timeout
115+
remove_noti_timeout ();
116+
117+
// Clear gesture/controller references
118+
gesture = null;
119+
motion_controller = null;
120+
121+
base.dispose ();
122+
}
123+
108124
/** Show a non-timed notification */
109125
public Notification.regular (NotifyParams param,
110126
NotificationType notification_type) {
@@ -344,8 +360,23 @@ namespace SwayNotificationCenter {
344360
string img = Functions.uri_to_path (img_paths[0]);
345361
File file = File.new_for_path (img);
346362
if (img.length > 0 && file.query_exists ()) {
347-
Gdk.Texture texture = Gdk.Texture.from_file (file);
348-
body_image.set_paintable (texture);
363+
// Clear previous body image to release GPU memory
364+
body_image.set_paintable (null);
365+
// Load image scaled to display size to save GPU memory
366+
// Full-res images (e.g., 2560x1440 screenshots) waste VRAM
367+
try {
368+
Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file_at_scale (
369+
img,
370+
notification_body_image_width * get_scale_factor (),
371+
notification_body_image_height * get_scale_factor (),
372+
true); // preserve aspect ratio
373+
Gdk.Texture texture = Gdk.Texture.for_pixbuf (pixbuf);
374+
body_image.set_paintable (texture);
375+
} catch (Error e) {
376+
// Fallback to full-size load if scaling fails
377+
Gdk.Texture texture = Gdk.Texture.from_file (file);
378+
body_image.set_paintable (texture);
379+
}
349380
body_image.set_can_shrink (true);
350381
body_image.set_content_fit (Gtk.ContentFit.SCALE_DOWN);
351382
body_image.width_request = notification_body_image_width;

0 commit comments

Comments
 (0)