Possible performance bug in gdk-pixbuf2

Hello Everyone

I found what appears to be a performance regression in gdk-pixbuf2. But I’m not quiet sure yet and I’d like to get a developers opinion before I make a bug report.

I use the Unity game engine on Fedora KDE 43. After switching from Fedora 42 to 43 I noticed that opening menus and context menus in Unity had become much slower than before, opening a menu takes about 1 second when it was instantaneous before. I’m not the only user affected by this issue, others have reported the same issue. You can find the relevant topic on the Unity forum here.

Internally, Unity uses gtk-3 to display menus, context menus and dialog boxes. After investigating the issue, it turned out that the performance regression was caused by gdk-pixbuf2 switching to glycin. Whenever I open a menu or a context menu, the glycin loader is being called constantly, causing performance issues. I found a mention of a similar issue in another gtk-3 application on the Arch Linux forum here.

After investigating further, I noticed that the issues is being called by this line in KDE’s Breeze theme:

check:checked {
    -gtk-icon-source: -gtk-recolor(url("../assets/checkmark-symbolic.svg")); }

Changing this line to the following completely solves the performance issue:

check:checked {
    -gtk-icon-source: url("../assets/checkmark-symbolic.svg"); }

Therefore, for whatever reason, -gtk-recolor is causing gdk-pixbuf2 to call the glycin loader in a loop.

This is not exclusive to KDE’s Breeze theme. I’m having the exact same issue with Adwaita. The difference being that with Adwaita I wasn’t able to figure out which image is being loaded (I assume it’s being loaded from memory rather than from a file).

Should I create a bug report for this and, if so, where?

Thank you very much.

1 Like

That sounds like the application might be triggering frequent icon changes, possibly due to changes in CSS pseudo classes. Maybe something weird is going on with focus/hover that causes frequent changes of the text-color which then requires rerendering of the recolored icon.

I’d suggest investigating how gtk_css_image_recolor_load() ends up getting called so frequently by looking at some backtraces using gdb.

I think part of the problem might be that gtk_css_image_recolor_load() always creates a new icon info and that means the symbolic_pixbuf_cache will always be empty. Thus the icon will have to be reloaded every time gtk_css_image_recolor_load() is called. That’s at least what I can see for the menus in gtk3-widget-factory.

Creating some cache for the icon info based on the path + scale might help. I quickly hacked this together to confirm my suspicion:

diff --git a/gtk/gtkcssimagerecolor.c b/gtk/gtkcssimagerecolor.c
index 1c38654cfa..9fa181ca0b 100644
--- a/gtk/gtkcssimagerecolor.c
+++ b/gtk/gtkcssimagerecolor.c
@@ -111,12 +111,27 @@ gtk_css_image_recolor_load (GtkCssImageRecolor  *recolor,
   GdkPixbuf *pixbuf;
   GtkCssImage *image;
   GError *local_error = NULL;
+  static GHashTable *info_cache = NULL;
+  char *image_uri = NULL;
 
   lookup_symbolic_colors (style, palette, &fg, &success, &warning, &error);
 
-  info = gtk_icon_info_new_for_file (url->file, 0, scale);
+  if (!info_cache)
+    info_cache = g_hash_table_new (g_str_hash, g_str_equal);
+
+  image_uri = g_file_get_uri (url->file);
+  info = g_hash_table_lookup (info_cache, image_uri);
+  if (info)
+    {
+      g_clear_pointer (&image_uri, g_free);
+    }
+  else
+    {
+      info = gtk_icon_info_new_for_file (url->file, 0, scale);
+      g_hash_table_insert (info_cache, image_uri, info);
+    }
+
   pixbuf = gtk_icon_info_load_symbolic (info, &fg, &success, &warning, &error, NULL, &local_error);
-  g_object_unref (info);
 
   if (pixbuf == NULL)
     {

With this I don’t see any more unnecessary reloads for symbolic menu icons in gtk3-widget-factory. This is far from a proper fix though. It does not ever clear the cache nor does it consider the scale.

So I would suggest reporting this issue against gtk here: Issues · GNOME / gtk · GitLab

Hello and thank you for your answer.

I opened a bug report here.

I have been unable to put a breakpoint into gtk_css_image_recolor_load() so I cannot confirm that it is the cause of the issue. But that seems likely.