forked from AuroraMiddleware/gtk
Merge branch 'wip/chergert/fix-ngl-cache-eviction' into 'master'
fix ngl cache eviction Closes #3771 See merge request GNOME/gtk!3316
This commit is contained in:
commit
b962a0f166
@ -39,6 +39,7 @@
|
|||||||
#include "gskngltexturepoolprivate.h"
|
#include "gskngltexturepoolprivate.h"
|
||||||
|
|
||||||
#define ATLAS_SIZE 512
|
#define ATLAS_SIZE 512
|
||||||
|
#define MAX_OLD_RATIO 0.5
|
||||||
|
|
||||||
typedef struct _GskNglTextureState
|
typedef struct _GskNglTextureState
|
||||||
{
|
{
|
||||||
@ -494,6 +495,37 @@ failure:
|
|||||||
return g_steal_pointer (&driver);
|
return g_steal_pointer (&driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GPtrArray *
|
||||||
|
gsk_ngl_driver_compact_atlases (GskNglDriver *self)
|
||||||
|
{
|
||||||
|
GPtrArray *removed = NULL;
|
||||||
|
|
||||||
|
g_assert (GSK_IS_NGL_DRIVER (self));
|
||||||
|
|
||||||
|
for (guint i = self->atlases->len; i > 0; i--)
|
||||||
|
{
|
||||||
|
GskNglTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1);
|
||||||
|
|
||||||
|
if (gsk_ngl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO)
|
||||||
|
{
|
||||||
|
GSK_NOTE (GLYPH_CACHE,
|
||||||
|
g_message ("Dropping atlas %d (%g.2%% old)", i,
|
||||||
|
100.0 * gsk_ngl_texture_atlas_get_unused_ratio (atlas)));
|
||||||
|
if (removed == NULL)
|
||||||
|
removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_ngl_texture_atlas_free);
|
||||||
|
g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GSK_NOTE (GLYPH_CACHE, {
|
||||||
|
static guint timestamp;
|
||||||
|
if (timestamp++ % 60 == 0)
|
||||||
|
g_message ("%d atlases", self->atlases->len);
|
||||||
|
});
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gsk_ngl_driver_begin_frame:
|
* gsk_ngl_driver_begin_frame:
|
||||||
* @self: a #GskNglDriver
|
* @self: a #GskNglDriver
|
||||||
@ -510,6 +542,7 @@ gsk_ngl_driver_begin_frame (GskNglDriver *self,
|
|||||||
GskNglCommandQueue *command_queue)
|
GskNglCommandQueue *command_queue)
|
||||||
{
|
{
|
||||||
gint64 last_frame_id;
|
gint64 last_frame_id;
|
||||||
|
GPtrArray *removed;
|
||||||
|
|
||||||
g_return_if_fail (GSK_IS_NGL_DRIVER (self));
|
g_return_if_fail (GSK_IS_NGL_DRIVER (self));
|
||||||
g_return_if_fail (GSK_IS_NGL_COMMAND_QUEUE (command_queue));
|
g_return_if_fail (GSK_IS_NGL_COMMAND_QUEUE (command_queue));
|
||||||
@ -524,8 +557,18 @@ gsk_ngl_driver_begin_frame (GskNglDriver *self,
|
|||||||
|
|
||||||
gsk_ngl_command_queue_begin_frame (self->command_queue);
|
gsk_ngl_command_queue_begin_frame (self->command_queue);
|
||||||
|
|
||||||
gsk_ngl_texture_library_begin_frame (GSK_NGL_TEXTURE_LIBRARY (self->icons));
|
/* Compact atlases with too many freed pixels */
|
||||||
gsk_ngl_texture_library_begin_frame (GSK_NGL_TEXTURE_LIBRARY (self->glyphs));
|
removed = gsk_ngl_driver_compact_atlases (self);
|
||||||
|
|
||||||
|
/* Mark unused pixel regions of the atlases */
|
||||||
|
gsk_ngl_texture_library_begin_frame (GSK_NGL_TEXTURE_LIBRARY (self->icons),
|
||||||
|
self->current_frame_id,
|
||||||
|
removed);
|
||||||
|
gsk_ngl_texture_library_begin_frame (GSK_NGL_TEXTURE_LIBRARY (self->glyphs),
|
||||||
|
self->current_frame_id,
|
||||||
|
removed);
|
||||||
|
|
||||||
|
/* Cleanup old shadows */
|
||||||
gsk_ngl_shadow_library_begin_frame (self->shadows);
|
gsk_ngl_shadow_library_begin_frame (self->shadows);
|
||||||
|
|
||||||
/* Remove all textures that are from a previous frame or are no
|
/* Remove all textures that are from a previous frame or are no
|
||||||
@ -534,6 +577,9 @@ gsk_ngl_driver_begin_frame (GskNglDriver *self,
|
|||||||
* we block on any resources while delivering our frames.
|
* we block on any resources while delivering our frames.
|
||||||
*/
|
*/
|
||||||
gsk_ngl_driver_collect_unused_textures (self, last_frame_id - 1);
|
gsk_ngl_driver_collect_unused_textures (self, last_frame_id - 1);
|
||||||
|
|
||||||
|
/* Now free atlas textures */
|
||||||
|
g_clear_pointer (&removed, g_ptr_array_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -553,9 +599,6 @@ gsk_ngl_driver_end_frame (GskNglDriver *self)
|
|||||||
gsk_ngl_command_queue_make_current (self->command_queue);
|
gsk_ngl_command_queue_make_current (self->command_queue);
|
||||||
gsk_ngl_command_queue_end_frame (self->command_queue);
|
gsk_ngl_command_queue_end_frame (self->command_queue);
|
||||||
|
|
||||||
gsk_ngl_texture_library_end_frame (GSK_NGL_TEXTURE_LIBRARY (self->icons));
|
|
||||||
gsk_ngl_texture_library_end_frame (GSK_NGL_TEXTURE_LIBRARY (self->glyphs));
|
|
||||||
|
|
||||||
self->in_frame = FALSE;
|
self->in_frame = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,16 @@ gsk_ngl_glyph_value_free (gpointer data)
|
|||||||
g_slice_free (GskNglGlyphValue, data);
|
g_slice_free (GskNglGlyphValue, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsk_ngl_glyph_library_begin_frame (GskNglTextureLibrary *library,
|
||||||
|
gint64 frame_id,
|
||||||
|
GPtrArray *removed_atlases)
|
||||||
|
{
|
||||||
|
GskNglGlyphLibrary *self = GSK_NGL_GLYPH_LIBRARY (library);
|
||||||
|
|
||||||
|
memset (self->front, 0, sizeof self->front);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gsk_ngl_glyph_library_finalize (GObject *object)
|
gsk_ngl_glyph_library_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
@ -98,8 +108,11 @@ static void
|
|||||||
gsk_ngl_glyph_library_class_init (GskNglGlyphLibraryClass *klass)
|
gsk_ngl_glyph_library_class_init (GskNglGlyphLibraryClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GskNglTextureLibraryClass *library_class = GSK_NGL_TEXTURE_LIBRARY_CLASS (klass);
|
||||||
|
|
||||||
object_class->finalize = gsk_ngl_glyph_library_finalize;
|
object_class->finalize = gsk_ngl_glyph_library_finalize;
|
||||||
|
|
||||||
|
library_class->begin_frame = gsk_ngl_glyph_library_begin_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -20,10 +20,14 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gsk/gskdebugprivate.h>
|
||||||
|
|
||||||
#include "gsknglcommandqueueprivate.h"
|
#include "gsknglcommandqueueprivate.h"
|
||||||
#include "gskngldriverprivate.h"
|
#include "gskngldriverprivate.h"
|
||||||
#include "gskngltexturelibraryprivate.h"
|
#include "gskngltexturelibraryprivate.h"
|
||||||
|
|
||||||
|
#define MAX_FRAME_AGE 60
|
||||||
|
|
||||||
G_DEFINE_ABSTRACT_TYPE (GskNglTextureLibrary, gsk_ngl_texture_library, G_TYPE_OBJECT)
|
G_DEFINE_ABSTRACT_TYPE (GskNglTextureLibrary, gsk_ngl_texture_library, G_TYPE_OBJECT)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -130,21 +134,62 @@ gsk_ngl_texture_library_set_funcs (GskNglTextureLibrary *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gsk_ngl_texture_library_begin_frame (GskNglTextureLibrary *self)
|
gsk_ngl_texture_library_begin_frame (GskNglTextureLibrary *self,
|
||||||
|
gint64 frame_id,
|
||||||
|
GPtrArray *removed_atlases)
|
||||||
{
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
|
||||||
g_return_if_fail (GSK_IS_NGL_TEXTURE_LIBRARY (self));
|
g_return_if_fail (GSK_IS_NGL_TEXTURE_LIBRARY (self));
|
||||||
|
|
||||||
if (GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame)
|
if (GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame)
|
||||||
GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self);
|
GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id, removed_atlases);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if (removed_atlases != NULL)
|
||||||
gsk_ngl_texture_library_end_frame (GskNglTextureLibrary *self)
|
{
|
||||||
{
|
GskNglTextureAtlasEntry *entry;
|
||||||
g_return_if_fail (GSK_IS_NGL_TEXTURE_LIBRARY (self));
|
guint dropped = 0;
|
||||||
|
|
||||||
if (GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->end_frame)
|
g_hash_table_iter_init (&iter, self->hash_table);
|
||||||
GSK_NGL_TEXTURE_LIBRARY_GET_CLASS (self)->end_frame (self);
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry))
|
||||||
|
{
|
||||||
|
if (entry->is_atlased)
|
||||||
|
{
|
||||||
|
for (guint i = 0; i < removed_atlases->len; i++)
|
||||||
|
{
|
||||||
|
GskNglTextureAtlas *atlas = g_ptr_array_index (removed_atlases, i);
|
||||||
|
|
||||||
|
if (atlas == entry->atlas)
|
||||||
|
{
|
||||||
|
g_hash_table_iter_remove (&iter);
|
||||||
|
dropped++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GSK_NOTE (GLYPH_CACHE,
|
||||||
|
if (dropped > 0)
|
||||||
|
g_message ("%s: Dropped %d icons",
|
||||||
|
G_OBJECT_TYPE_NAME (self), dropped));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_id % MAX_FRAME_AGE == 0)
|
||||||
|
{
|
||||||
|
GskNglTextureAtlasEntry *entry;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, self->hash_table);
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry))
|
||||||
|
{
|
||||||
|
gsk_ngl_texture_atlas_entry_mark_unused (entry);
|
||||||
|
entry->accessed = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSK_NOTE (GLYPH_CACHE, g_message ("%s: %d atlas items cached",
|
||||||
|
G_OBJECT_TYPE_NAME (self),
|
||||||
|
g_hash_table_size (self->hash_table)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GskNglTexture *
|
static GskNglTexture *
|
||||||
@ -252,6 +297,7 @@ gsk_ngl_texture_library_pack (GskNglTextureLibrary *self,
|
|||||||
entry = g_slice_alloc0 (valuelen);
|
entry = g_slice_alloc0 (valuelen);
|
||||||
entry->n_pixels = width * height;
|
entry->n_pixels = width * height;
|
||||||
entry->accessed = TRUE;
|
entry->accessed = TRUE;
|
||||||
|
entry->used = TRUE;
|
||||||
|
|
||||||
/* If our size is invisible then we just want an entry in the
|
/* If our size is invisible then we just want an entry in the
|
||||||
* cache for faster lookups, but do not actually spend any texture
|
* cache for faster lookups, but do not actually spend any texture
|
||||||
|
@ -99,8 +99,9 @@ typedef struct _GskNglTextureLibraryClass
|
|||||||
{
|
{
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
|
|
||||||
void (*begin_frame) (GskNglTextureLibrary *library);
|
void (*begin_frame) (GskNglTextureLibrary *library,
|
||||||
void (*end_frame) (GskNglTextureLibrary *library);
|
gint64 frame_id,
|
||||||
|
GPtrArray *removed_atlases);
|
||||||
} GskNglTextureLibraryClass;
|
} GskNglTextureLibraryClass;
|
||||||
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskNglTextureLibrary, g_object_unref)
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskNglTextureLibrary, g_object_unref)
|
||||||
@ -111,8 +112,9 @@ void gsk_ngl_texture_library_set_funcs (GskNglTextureLibrary *self,
|
|||||||
GEqualFunc equal_func,
|
GEqualFunc equal_func,
|
||||||
GDestroyNotify key_destroy,
|
GDestroyNotify key_destroy,
|
||||||
GDestroyNotify value_destroy);
|
GDestroyNotify value_destroy);
|
||||||
void gsk_ngl_texture_library_begin_frame (GskNglTextureLibrary *self);
|
void gsk_ngl_texture_library_begin_frame (GskNglTextureLibrary *self,
|
||||||
void gsk_ngl_texture_library_end_frame (GskNglTextureLibrary *self);
|
gint64 frame_id,
|
||||||
|
GPtrArray *removed_atlases);
|
||||||
gpointer gsk_ngl_texture_library_pack (GskNglTextureLibrary *self,
|
gpointer gsk_ngl_texture_library_pack (GskNglTextureLibrary *self,
|
||||||
gpointer key,
|
gpointer key,
|
||||||
gsize valuelen,
|
gsize valuelen,
|
||||||
@ -126,14 +128,29 @@ static inline void
|
|||||||
gsk_ngl_texture_atlas_mark_unused (GskNglTextureAtlas *self,
|
gsk_ngl_texture_atlas_mark_unused (GskNglTextureAtlas *self,
|
||||||
int n_pixels)
|
int n_pixels)
|
||||||
{
|
{
|
||||||
|
g_assert (n_pixels >= 0);
|
||||||
|
|
||||||
self->unused_pixels += n_pixels;
|
self->unused_pixels += n_pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
gsk_ngl_texture_atlas_mark_used (GskNglTextureAtlas *self,
|
gsk_ngl_texture_atlas_entry_mark_used (GskNglTextureAtlasEntry *entry)
|
||||||
int n_pixels)
|
|
||||||
{
|
{
|
||||||
self->unused_pixels -= n_pixels;
|
if (entry->used == TRUE || entry->is_atlased == FALSE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entry->atlas->unused_pixels -= entry->n_pixels;
|
||||||
|
entry->used = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
gsk_ngl_texture_atlas_entry_mark_unused (GskNglTextureAtlasEntry *entry)
|
||||||
|
{
|
||||||
|
if (entry->used == FALSE || entry->is_atlased == FALSE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entry->atlas->unused_pixels += entry->n_pixels;
|
||||||
|
entry->used = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
@ -151,13 +168,7 @@ gsk_ngl_texture_library_lookup (GskNglTextureLibrary *self,
|
|||||||
|
|
||||||
if (entry != NULL)
|
if (entry != NULL)
|
||||||
{
|
{
|
||||||
if (!entry->used && entry->is_atlased)
|
gsk_ngl_texture_atlas_entry_mark_used (entry);
|
||||||
{
|
|
||||||
g_assert (entry->atlas != NULL);
|
|
||||||
gsk_ngl_texture_atlas_mark_used (entry->atlas, entry->n_pixels);
|
|
||||||
entry->used = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->accessed = TRUE;
|
entry->accessed = TRUE;
|
||||||
*out_entry = entry;
|
*out_entry = entry;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
Loading…
Reference in New Issue
Block a user