inspector: Speed up the fps overlay
authorMatthias Clasen <mclasen@redhat.com>
Wed, 1 Nov 2023 17:55:29 +0000 (13:55 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 17 Nov 2023 20:28:58 +0000 (15:28 -0500)
Do less work!

gtk/inspector/fpsoverlay.c

index 63c948259b413d120bb4ec8ecc4a4ddbd3415361..a5aa45275cecbdc6e1e7448a473edb27346c9a54 100644 (file)
@@ -24,6 +24,7 @@
 #include "gtkwidget.h"
 #include "gtkwindow.h"
 #include "gtknative.h"
+#include "gtkmain.h"
 
 /* duration before we start fading in us */
 #define GDK_FPS_OVERLAY_LINGER_DURATION (1000 * 1000)
@@ -40,6 +41,11 @@ struct _GtkFpsOverlay
   GtkInspectorOverlay parent_instance;
 
   GHashTable *infos; /* GtkWidget => GtkFpsInfo */
+
+  PangoFont *font;
+  PangoGlyphString *glyphs;
+  PangoGlyphString *digits;
+  int width, height, baseline;
 };
 
 struct _GtkFpsOverlayClass
@@ -89,15 +95,13 @@ gtk_fps_overlay_snapshot (GtkInspectorOverlay *overlay,
 {
   GtkFpsOverlay *self = GTK_FPS_OVERLAY (overlay);
   GtkFpsInfo *info;
-  PangoLayout *layout;
-  PangoAttrList *attrs;
   gint64 now;
   double fps;
-  char *fps_string;
   graphene_rect_t bounds;
   gboolean has_bounds;
-  int width, height;
   double overlay_opacity;
+  PangoGlyphString *glyphs;
+  GskRenderNode *fps_node;
 
   now = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
   info = g_hash_table_lookup (self->infos, widget);
@@ -131,12 +135,6 @@ gtk_fps_overlay_snapshot (GtkInspectorOverlay *overlay,
         }
     }
 
-  fps = gtk_fps_overlay_get_fps (widget);
-  if (fps == 0.0)
-    fps_string = g_strdup ("--- fps");
-  else
-    fps_string = g_strdup_printf ("%.2f fps", fps);
-
   if (GTK_IS_WINDOW (widget))
     {
       GtkWidget *child = gtk_window_get_child (GTK_WINDOW (widget));
@@ -146,33 +144,50 @@ gtk_fps_overlay_snapshot (GtkInspectorOverlay *overlay,
       else
         has_bounds = gtk_widget_compute_bounds (child, widget, &bounds);
     }
-  else
+   else
     {
       has_bounds = gtk_widget_compute_bounds (widget, widget, &bounds);
     }
 
-  layout = gtk_widget_create_pango_layout (widget, fps_string);
-  attrs = pango_attr_list_new ();
-  pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum=1"));
-  pango_layout_set_attributes (layout, attrs);
-  pango_attr_list_unref (attrs);
-  pango_layout_get_pixel_size (layout, &width, &height);
+  glyphs = pango_glyph_string_copy (self->glyphs);
+
+  fps = gtk_fps_overlay_get_fps (widget);
+  if (fps == 0.0)
+    {
+      for (int i = 0; i < 7; i++)
+        glyphs->glyphs[i].glyph = PANGO_GLYPH_EMPTY;
+    }
+  else
+    {
+      char *fps_string = g_strdup_printf ("%7.2f fps", fps);
+      for (int i = 0; i < 7; i++)
+        {
+          if (g_ascii_isdigit (fps_string[i]))
+            glyphs->glyphs[i].glyph = self->digits->glyphs[fps_string[i] - '0'].glyph;
+          else if (fps_string[i] == ' ')
+            glyphs->glyphs[i].glyph = PANGO_GLYPH_EMPTY;
+        }
+      g_free (fps_string);
+    }
 
   gtk_snapshot_save (snapshot);
   if (has_bounds)
-    gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (bounds.origin.x + bounds.size.width - width, bounds.origin.y));
+    gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (bounds.origin.x + bounds.size.width - self->width, bounds.origin.y));
+
   if (overlay_opacity < 1.0)
     gtk_snapshot_push_opacity (snapshot, overlay_opacity);
   gtk_snapshot_append_color (snapshot,
                              &(GdkRGBA) { 0, 0, 0, 0.5 },
-                             &GRAPHENE_RECT_INIT (-1, -1, width + 2, height + 2));
-  gtk_snapshot_append_layout (snapshot,
-                              layout,
-                              &(GdkRGBA) { 1, 1, 1, 1 });
+                             &GRAPHENE_RECT_INIT (-1, -1, self->width + 2, self->height + 2));
+  fps_node = gsk_text_node_new (self->font,
+                                glyphs,
+                                &(GdkRGBA) { 1, 1, 1, 1 },
+                                &GRAPHENE_POINT_INIT (0, self->baseline));
+  gtk_snapshot_append_node (snapshot, fps_node);
+  gsk_render_node_unref (fps_node);
   if (overlay_opacity < 1.0)
     gtk_snapshot_pop (snapshot);
   gtk_snapshot_restore (snapshot);
-  g_free (fps_string);
 
   gtk_widget_add_tick_callback (widget, gtk_fps_overlay_force_redraw, NULL, NULL);
 }
@@ -196,6 +211,10 @@ gtk_fps_overlay_dispose (GObject *object)
 
   g_hash_table_unref (self->infos);
 
+  g_clear_pointer (&self->glyphs, pango_glyph_string_free);
+  g_clear_pointer (&self->digits, pango_glyph_string_free);
+  g_clear_object (&self->font);
+
   G_OBJECT_CLASS (gtk_fps_overlay_parent_class)->dispose (object);
 }
 
@@ -214,7 +233,44 @@ gtk_fps_overlay_class_init (GtkFpsOverlayClass *klass)
 static void
 gtk_fps_overlay_init (GtkFpsOverlay *self)
 {
+  PangoContext *context;
+  PangoLayout *layout;
+  PangoLayoutIter *iter;
+  PangoLayoutRun *run;
+  PangoAttrList *attrs;
+
   self->infos = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gtk_fps_info_free);
+
+  context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
+  pango_context_set_language (context, gtk_get_default_language ());
+
+  layout = pango_layout_new (context);
+  pango_layout_set_text (layout, "0000.00 fps", -1);
+  attrs = pango_attr_list_new ();
+  pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum=1"));
+  pango_layout_set_attributes (layout, attrs);
+  pango_attr_list_unref (attrs);
+  pango_layout_get_pixel_size (layout, &self->width, &self->height);
+
+  iter = pango_layout_get_iter (layout);
+  self->baseline = pango_layout_iter_get_baseline (iter) / (double) PANGO_SCALE;
+  run = pango_layout_iter_get_run_readonly (iter);
+
+  self->glyphs = pango_glyph_string_copy (run->glyphs);
+  self->font = g_object_ref (run->item->analysis.font);
+
+  pango_layout_iter_free (iter);
+
+  pango_layout_set_text (layout, "0123456789", -1);
+
+  iter = pango_layout_get_iter (layout);
+  run = pango_layout_iter_get_run_readonly (iter);
+
+  self->digits = pango_glyph_string_copy (run->glyphs);
+
+  pango_layout_iter_free (iter);
+  g_object_unref (layout);
+  g_object_unref (context);
 }
 
 GtkInspectorOverlay *