[gtk/mask-nodes: 38/39] gl: Add a path cache




commit 4d4993b8ae843ee65a35b844ae84a4b98472810b
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 20 21:46:00 2020 -0500

    gl: Add a path cache
    
    This is very similar to the shadow cache.
    We cache masks that we've rendered for paths,
    including the fill rule and the stroke parameters
    in the key.
    The cache is not used yet.

 gsk/gl/gskglpathcache.c        | 157 +++++++++++++++++++++++++++++++++++++++++
 gsk/gl/gskglpathcacheprivate.h |  31 ++++++++
 gsk/gl/gskglrenderer.c         |   5 ++
 gsk/meson.build                |   1 +
 4 files changed, 194 insertions(+)
---
diff --git a/gsk/gl/gskglpathcache.c b/gsk/gl/gskglpathcache.c
new file mode 100644
index 0000000000..1dcb0c33d8
--- /dev/null
+++ b/gsk/gl/gskglpathcache.c
@@ -0,0 +1,157 @@
+#include "config.h"
+
+#include "gskglpathcacheprivate.h"
+#include "gskstrokeprivate.h"
+
+#define MAX_UNUSED_FRAMES (16 * 5)
+
+typedef struct
+{
+  GskPath *path;
+  GskFillRule fill_rule;
+  const GskStroke *stroke;
+  guint hash;
+
+  GskStroke stroke_copy;
+  graphene_rect_t bounds;
+  int texture_id;
+  int unused_frames;
+} CacheItem;
+
+static guint
+compute_hash (CacheItem *item)
+{
+  guint hash;
+
+  hash = GPOINTER_TO_UINT (item->path);
+  hash += item->fill_rule;
+  if (item->stroke)
+    hash += gsk_stroke_hash (item->stroke);
+
+  return hash;
+}
+
+static guint
+cache_key_hash (gconstpointer v)
+{
+  const CacheItem *item = v;
+
+  return item->hash;
+}
+
+static gboolean
+cache_key_equal (gconstpointer v1,
+                 gconstpointer v2)
+{
+  const CacheItem *item1 = v1;
+  const CacheItem *item2 = v2;
+
+  return item1->path == item2->path &&
+         item1->fill_rule == item2->fill_rule &&
+         (item1->stroke == item2->stroke ||
+          (item1->stroke && item2->stroke &&
+           gsk_stroke_equal (item1->stroke, item2->stroke)));
+}
+
+void
+gsk_gl_path_cache_init (GskGLPathCache *self)
+{
+  self->textures = g_hash_table_new_full (cache_key_hash,
+                                          cache_key_equal,
+                                          NULL,
+                                          g_free);
+}
+
+void
+gsk_gl_path_cache_free (GskGLPathCache *self,
+                        GskGLDriver    *gl_driver)
+{
+  GHashTableIter iter;
+  CacheItem *item;
+
+  g_hash_table_iter_init (&iter, self->textures);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&item))
+    {
+      gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
+    }
+
+  g_hash_table_unref (self->textures);
+  self->textures = NULL;
+}
+
+void
+gsk_gl_path_cache_begin_frame (GskGLPathCache *self,
+                               GskGLDriver    *gl_driver)
+{
+  GHashTableIter iter;
+  CacheItem *item;
+
+  g_hash_table_iter_init (&iter, self->textures);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&item))
+    {
+      if (item->unused_frames > MAX_UNUSED_FRAMES)
+        {
+          gsk_gl_driver_destroy_texture (gl_driver, item->texture_id);
+          g_hash_table_iter_remove (&iter);
+        }
+    }
+}
+
+int
+gsk_gl_path_cache_get_texture_id (GskGLPathCache  *self,
+                                  GskPath         *path,
+                                  GskFillRule      fill_rule,
+                                  const GskStroke *stroke,
+                                  graphene_rect_t *out_bounds)
+{
+  CacheItem key;
+  CacheItem *item;
+
+  key.path = path;
+  key.fill_rule = fill_rule;
+  key.stroke = stroke;
+  key.hash = compute_hash (&key);
+
+  item = g_hash_table_lookup (self->textures, &key);
+  if (item == NULL)
+    return 0;
+
+  item->unused_frames = 0;
+
+  g_assert (item->texture_id != 0);
+
+  *out_bounds = item->bounds;
+
+  return item->texture_id;
+}
+
+void
+gsk_gl_path_cache_commit (GskGLPathCache        *self,
+                          GskPath               *path,
+                          GskFillRule            fill_rule,
+                          const GskStroke       *stroke,
+                          int                    texture_id,
+                          const graphene_rect_t *bounds)
+{
+  CacheItem *item;
+
+  g_assert (self != NULL);
+  g_assert (texture_id > 0);
+
+  item = g_new0 (CacheItem, 1);
+
+  item->path = path;
+  item->fill_rule = fill_rule;
+  if (stroke)
+    {
+      gsk_stroke_init_copy (&item->stroke_copy, stroke);
+      item->stroke = &item->stroke_copy;
+    }
+  item->hash = compute_hash (item);
+
+  item->unused_frames = 0;
+  item->texture_id = texture_id;
+  item->bounds = *bounds;
+
+  g_hash_table_add (self->textures, item);
+}
diff --git a/gsk/gl/gskglpathcacheprivate.h b/gsk/gl/gskglpathcacheprivate.h
new file mode 100644
index 0000000000..181d4be26f
--- /dev/null
+++ b/gsk/gl/gskglpathcacheprivate.h
@@ -0,0 +1,31 @@
+#ifndef __GSK_GL_PATH_CACHE_H__
+#define __GSK_GL_PATH_CACHE_H__
+
+#include <glib.h>
+#include "gskgldriverprivate.h"
+#include "gskpath.h"
+
+typedef struct
+{
+  GHashTable *textures;
+} GskGLPathCache;
+
+
+void gsk_gl_path_cache_init           (GskGLPathCache        *self);
+void gsk_gl_path_cache_free           (GskGLPathCache        *self,
+                                       GskGLDriver           *gl_driver);
+void gsk_gl_path_cache_begin_frame    (GskGLPathCache        *self,
+                                       GskGLDriver           *gl_driver);
+int  gsk_gl_path_cache_get_texture_id (GskGLPathCache        *self,
+                                       GskPath               *path,
+                                       GskFillRule            fill_rule,
+                                       const GskStroke       *stroke,
+                                       graphene_rect_t       *out_bounds);
+void gsk_gl_path_cache_commit         (GskGLPathCache        *self,
+                                       GskPath               *path,
+                                       GskFillRule            fill_rule,
+                                       const GskStroke       *stroke,
+                                       int                    texture_id,
+                                       const graphene_rect_t *bounds);
+
+#endif
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index c00805c6e5..09b7b4f0a1 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -16,6 +16,7 @@
 #include "gskglrenderopsprivate.h"
 #include "gskcairoblurprivate.h"
 #include "gskglshadowcacheprivate.h"
+#include "gskglpathcacheprivate.h"
 #include "gskglnodesampleprivate.h"
 #include "gsktransform.h"
 #include "glutilsprivate.h"
@@ -542,6 +543,7 @@ struct _GskGLRenderer
   GskGLGlyphCache *glyph_cache;
   GskGLIconCache *icon_cache;
   GskGLShadowCache shadow_cache;
+  GskGLPathCache path_cache;
 
 #ifdef G_ENABLE_DEBUG
   struct {
@@ -3636,6 +3638,7 @@ gsk_gl_renderer_realize (GskRenderer  *renderer,
   self->glyph_cache = get_glyph_cache_for_display (gdk_surface_get_display (surface), self->atlases);
   self->icon_cache = get_icon_cache_for_display (gdk_surface_get_display (surface), self->atlases);
   gsk_gl_shadow_cache_init (&self->shadow_cache);
+  gsk_gl_path_cache_init (&self->path_cache);
 
   gdk_profiler_end_mark (before, "gl renderer realize", NULL);
 
@@ -3663,6 +3666,7 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
   g_clear_pointer (&self->icon_cache, gsk_gl_icon_cache_unref);
   g_clear_pointer (&self->atlases, gsk_gl_texture_atlases_unref);
   gsk_gl_shadow_cache_free (&self->shadow_cache, self->gl_driver);
+  gsk_gl_path_cache_free (&self->path_cache, self->gl_driver);
 
   g_clear_object (&self->gl_profiler);
   g_clear_object (&self->gl_driver);
@@ -4304,6 +4308,7 @@ gsk_gl_renderer_do_render (GskRenderer           *renderer,
   gsk_gl_glyph_cache_begin_frame (self->glyph_cache, self->gl_driver, removed);
   gsk_gl_icon_cache_begin_frame (self->icon_cache, removed);
   gsk_gl_shadow_cache_begin_frame (&self->shadow_cache, self->gl_driver);
+  gsk_gl_path_cache_begin_frame (&self->path_cache, self->gl_driver);
   g_ptr_array_unref (removed);
 
   /* Set up the modelview and projection matrices to fit our viewport */
diff --git a/gsk/meson.build b/gsk/meson.build
index 5925594c29..618ed14651 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -59,6 +59,7 @@ gsk_private_sources = files([
   'gl/gskgliconcache.c',
   'gl/opbuffer.c',
   'gl/stb_rect_pack.c',
+  'gl/gskglpathcache.c',
 ])
 
 gsk_public_headers = files([


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]