Subject: Re: bug#68006: 30.0.50; Image-mode speed

From: Manuel Giraud <[email-masked]>
Date: Sat, 06 Jan 2024 14:07:37 +0100

Hi,

Here is a diff of where I'm headed to.  'user-image-cache' is not used
at all yet.  I imagine that a user could fill it with a call to
'make-image-cache' (when it exists).  Anyway, WDYT?

diff --git a/src/image.c b/src/image.c
index 252b83da992..27d564fb49c 100644
--- a/src/image.c
+++ b/src/image.c
@@ -2086,7 +2086,7 @@ image_alloc_image_color (struct frame *f, struct image *img,
 			     Image Cache
  ***********************************************************************/
 
-static void cache_image (struct frame *f, struct image *img);
+static void cache_image (struct image_cache **pc, struct image *img);
 
 /* Return a new, initialized image cache that is allocated from the
    heap.  Call free_image_cache to free an image cache.  */
@@ -2103,15 +2103,14 @@ make_image_cache (void)
   return c;
 }
 
-/* Find an image matching SPEC in the cache, and return it.  If no
+/* Find an image matching SPEC in the cache C, and return it.  If no
    image is found, return NULL.  */
 static struct image *
-search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash,
+search_image_cache (struct image_cache *c, Lisp_Object spec, EMACS_UINT hash,
                     unsigned long foreground, unsigned long background,
                     int font_size, char *font_family, bool ignore_colors)
 {
   struct image *img;
-  struct image_cache *c = FRAME_IMAGE_CACHE (f);
   int i = hash % IMAGE_CACHE_BUCKETS_SIZE;
 
   if (!c) return NULL;
@@ -2185,12 +2184,13 @@ uncache_image (struct frame *f, Lisp_Object spec)
 {
   struct image *img;
   EMACS_UINT hash = sxhash (filter_image_spec (spec));
+  struct image_cache *cache = FRAME_IMAGE_CACHE (f);
 
   /* Because the background colors are based on the current face, we
      can have multiple copies of an image with the same spec. We want
      to remove them all to ensure the user doesn't see an old version
      of the image when the face changes.  */
-  while ((img = search_image_cache (f, spec, hash, 0, 0, 0, NULL, true)))
+  while ((img = search_image_cache (cache, spec, hash, 0, 0, 0, NULL, true)))
     {
       free_image (f, img);
       /* As display glyphs may still be referring to the image ID, we
@@ -3359,6 +3359,7 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
   unsigned long background = face->background;
   int font_size = face->font->pixel_size;
   char *font_family = SSDATA (face->lface[LFACE_FAMILY_INDEX]);
+  struct image_cache *cache;
 
   /* F must be a window-system frame, and SPEC must be a valid image
      specification.  */
@@ -3367,7 +3368,13 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (filter_image_spec (spec));
-  img = search_image_cache (f, spec, hash, foreground, background,
+
+  if (!NILP (Vuser_image_cache))
+    cache = XUNTAG (Vuser_image_cache, Lisp_Vectorlike, struct image_cache);
+  else
+    cache = FRAME_IMAGE_CACHE (f);
+  
+  img = search_image_cache (cache, spec, hash, foreground, background,
 			    font_size, font_family, false);
   if (img && img->load_failed_p)
     {
@@ -3380,7 +3387,7 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
     {
       block_input ();
       img = make_image (spec, hash);
-      cache_image (f, img);
+      cache_image (&cache, img);
       img->face_foreground = foreground;
       img->face_background = background;
       img->face_font_size = font_size;
@@ -3470,16 +3477,17 @@ lookup_image (struct frame *f, Lisp_Object spec, int face_id)
 }

-/* Cache image IMG in the image cache of frame F.  */
+/* Cache image IMG in the image cache C.  */
 
 static void
-cache_image (struct frame *f, struct image *img)
+cache_image (struct image_cache **pc, struct image *img)
 {
-  struct image_cache *c = FRAME_IMAGE_CACHE (f);
+  struct image_cache *c;
   ptrdiff_t i;
 
-  if (!c)
-    c = FRAME_IMAGE_CACHE (f) = make_image_cache ();
+  if (!*pc)
+    *pc = make_image_cache ();
+  c = *pc;
 
   /* Find a free slot in c->images.  */
   for (i = 0; i < c->used; ++i)
@@ -12975,6 +12983,10 @@ syms_of_image (void)
 
 The function `clear-image-cache' disregards this variable.  */);
   Vimage_cache_eviction_delay = make_fixnum (300);
+
+  DEFVAR_LISP ("user-image-cache", Vuser_image_cache,
+    doc: /* TBD.  */);
+  Vuser_image_cache = Qnil;
 #ifdef HAVE_IMAGEMAGICK
   DEFVAR_INT ("imagemagick-render-type", imagemagick_render_type,
     doc: /* Integer indicating which ImageMagick rendering method to use.

-- 
Manuel Giraud