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
This commit is contained in:
Benjamin Otte 2024-08-21 09:44:24 +02:00
parent a196bf1132
commit c7fabe2897
3 changed files with 26 additions and 5 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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 ());
}
}