From c7fabe289725af9d95c70ce06d828727798165f8 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 21 Aug 2024 09:44:24 +0200 Subject: [PATCH] gpu: Be more aggressive about GC'ing dead textures When we encounter many dead textures, we want to GC. Textures can take up fds (potentially even more than 1) and when we are not collecting them quickly enough, we may run out of fds. So GC when more then 50 dead textures exist. An example for this happening is recent Mesa with llvmpipe udmabuf support, which takes 2 fds per texture and the test in testsuite/gdk/memorytexture that creates 800 textures of ~1 pixel each, which it diligently releases but doesn't GC. Related: #6917 --- gsk/gpu/gskgpucache.c | 22 ++++++++++++++++++++-- gsk/gpu/gskgpucacheprivate.h | 1 + gsk/gpu/gskgpudevice.c | 8 +++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/gsk/gpu/gskgpucache.c b/gsk/gpu/gskgpucache.c index 590b464192..724b9ecf57 100644 --- a/gsk/gpu/gskgpucache.c +++ b/gsk/gpu/gskgpucache.c @@ -48,6 +48,7 @@ struct _GskGpuCache GskGpuCachedAtlas *current_atlas; + /* atomic */ gsize dead_textures; /* atomic */ gsize dead_texture_pixels; }; @@ -372,6 +373,7 @@ struct _GskGpuCachedTexture * weak ref. */ + gsize *dead_textures_counter; gsize *dead_pixels_counter; GdkTexture *texture; @@ -470,7 +472,10 @@ gsk_gpu_cached_texture_destroy_cb (gpointer data) GskGpuCachedTexture *self = data; if (!gsk_gpu_cached_texture_is_invalid (self)) - g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels); + { + g_atomic_pointer_add (self->dead_textures_counter, 1); + g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels); + } if (g_atomic_int_dec_and_test (&self->use_count)) g_free (self); @@ -508,6 +513,7 @@ gsk_gpu_cached_texture_new (GskGpuCache *cache, self->image = g_object_ref (image); self->color_state = color_state; ((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image); + self->dead_textures_counter = &cache->dead_textures; self->dead_pixels_counter = &cache->dead_texture_pixels; self->use_count = 2; @@ -537,6 +543,7 @@ struct _GskGpuCachedTile * list) and by the texture (via weak ref) */ + gsize *dead_textures_counter; gsize *dead_pixels_counter; GskGpuImage *image; @@ -609,7 +616,10 @@ gsk_gpu_cached_tile_destroy_cb (gpointer data) GskGpuCachedTile *self = data; if (!gsk_gpu_cached_tile_is_invalid (self)) - g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels); + { + g_atomic_pointer_add (self->dead_textures_counter, 1); + g_atomic_pointer_add (self->dead_pixels_counter, ((GskGpuCached *) self)->pixels); + } if (g_atomic_int_dec_and_test (&self->use_count)) g_free (self); @@ -649,6 +659,7 @@ gsk_gpu_cached_tile_new (GskGpuCache *cache, self->image = g_object_ref (image); self->color_state = gdk_color_state_ref (color_state); ((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image); + self->dead_textures_counter = &cache->dead_textures; self->dead_pixels_counter = &cache->dead_texture_pixels; self->use_count = 2; @@ -894,6 +905,7 @@ gsk_gpu_cache_gc (GskGpuCache *self, is_empty &= cached->stale; } + g_atomic_pointer_set (&self->dead_textures, 0); g_atomic_pointer_set (&self->dead_texture_pixels, 0); if (GSK_DEBUG_CHECK (CACHE)) @@ -904,6 +916,12 @@ gsk_gpu_cache_gc (GskGpuCache *self, return is_empty; } +gsize +gsk_gpu_cache_get_dead_textures (GskGpuCache *self) +{ + return GPOINTER_TO_SIZE (g_atomic_pointer_get (&self->dead_textures)); +} + gsize gsk_gpu_cache_get_dead_texture_pixels (GskGpuCache *self) { diff --git a/gsk/gpu/gskgpucacheprivate.h b/gsk/gpu/gskgpucacheprivate.h index aa7ce2764c..9164504c76 100644 --- a/gsk/gpu/gskgpucacheprivate.h +++ b/gsk/gpu/gskgpucacheprivate.h @@ -64,6 +64,7 @@ void gsk_gpu_cache_set_time (GskGpuC gboolean gsk_gpu_cache_gc (GskGpuCache *self, gint64 cache_timeout, gint64 timestamp); +gsize gsk_gpu_cache_get_dead_textures (GskGpuCache *self); gsize gsk_gpu_cache_get_dead_texture_pixels (GskGpuCache *self); GskGpuImage * gsk_gpu_cache_get_atlas_image (GskGpuCache *self); diff --git a/gsk/gpu/gskgpudevice.c b/gsk/gpu/gskgpudevice.c index fff4426893..64d8189716 100644 --- a/gsk/gpu/gskgpudevice.c +++ b/gsk/gpu/gskgpudevice.c @@ -80,7 +80,7 @@ void gsk_gpu_device_maybe_gc (GskGpuDevice *self) { GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self); - gsize dead_texture_pixels; + gsize dead_texture_pixels, dead_textures; if (priv->cache_timeout < 0) return; @@ -88,11 +88,13 @@ gsk_gpu_device_maybe_gc (GskGpuDevice *self) if (priv->cache == NULL) return; + dead_textures = gsk_gpu_cache_get_dead_textures (priv->cache); dead_texture_pixels = gsk_gpu_cache_get_dead_texture_pixels (priv->cache); - if (priv->cache_timeout == 0 || dead_texture_pixels > 1000000) + if (priv->cache_timeout == 0 || dead_textures > 50 || dead_texture_pixels > 1000 * 1000) { - GSK_DEBUG (CACHE, "Pre-frame GC (%" G_GSIZE_FORMAT " dead pixels)", dead_texture_pixels); + GSK_DEBUG (CACHE, "Pre-frame GC (%" G_GSIZE_FORMAT " dead textures, %" G_GSIZE_FORMAT " dead pixels)", + dead_textures, dead_texture_pixels); gsk_gpu_device_gc (self, g_get_monotonic_time ()); } }