Cache thumbnails across reloads

This will speed up sort changes, as well as simple reloads,
at the cost of an extra hash map from URIs to Cairo surface references.

It seems unnecessary to provide an explicit option to flush this cache,
as it may be cleared by changing either the directory or the current
thumbnail size.
This commit is contained in:
Přemysl Eric Janouch 2022-06-04 16:28:18 +02:00
parent bb97445a96
commit 8bba456b14
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 34 additions and 7 deletions

View File

@ -72,6 +72,8 @@ struct _FivBrowser {
double drag_begin_x; ///< Viewport start X coordinate or -1 double drag_begin_x; ///< Viewport start X coordinate or -1
double drag_begin_y; ///< Viewport start Y coordinate or -1 double drag_begin_y; ///< Viewport start Y coordinate or -1
GHashTable *thumbnail_cache; ///< [URI]cairo_surface_t, for item_size
Thumbnailer *thumbnailers; ///< Parallelized thumbnailers Thumbnailer *thumbnailers; ///< Parallelized thumbnailers
size_t thumbnailers_len; ///< Thumbnailers array size size_t thumbnailers_len; ///< Thumbnailers array size
GList *thumbnailers_queue; ///< Queued up Entry pointers GList *thumbnailers_queue; ///< Queued up Entry pointers
@ -431,9 +433,18 @@ entry_add_thumbnail(gpointer data, gpointer user_data)
g_clear_pointer(&self->thumbnail, cairo_surface_destroy); g_clear_pointer(&self->thumbnail, cairo_surface_destroy);
FivBrowser *browser = FIV_BROWSER(user_data); FivBrowser *browser = FIV_BROWSER(user_data);
self->thumbnail = rescale_thumbnail( cairo_surface_t *cached =
fiv_thumbnail_lookup(self->uri, self->mtime_msec, browser->item_size), g_hash_table_lookup(browser->thumbnail_cache, self->uri);
browser->item_height); if (cached &&
(intptr_t) cairo_surface_get_user_data(
cached, &fiv_browser_key_mtime_msec) == self->mtime_msec) {
self->thumbnail = cairo_surface_reference(cached);
} else {
cairo_surface_t *found = fiv_thumbnail_lookup(
self->uri, self->mtime_msec, browser->item_size);
self->thumbnail = rescale_thumbnail(found, browser->item_height);
}
if (self->thumbnail) { if (self->thumbnail) {
// This choice of mtime favours unnecessary thumbnail reloading. // This choice of mtime favours unnecessary thumbnail reloading.
cairo_surface_set_user_data(self->thumbnail, cairo_surface_set_user_data(self->thumbnail,
@ -515,8 +526,18 @@ reload_thumbnails(FivBrowser *self)
g_thread_pool_push(pool, &g_array_index(self->entries, Entry, i), NULL); g_thread_pool_push(pool, &g_array_index(self->entries, Entry, i), NULL);
g_thread_pool_free(pool, FALSE, TRUE); g_thread_pool_free(pool, FALSE, TRUE);
for (guint i = 0; i < self->entries->len; i++) // Once a URI disappears from the model, its thumbnail is forgotten.
materialize_icon(self, &g_array_index(self->entries, Entry, i)); g_hash_table_remove_all(self->thumbnail_cache);
for (guint i = 0; i < self->entries->len; i++) {
Entry *entry = &g_array_index(self->entries, Entry, i);
if (entry->thumbnail) {
g_hash_table_insert(self->thumbnail_cache, g_strdup(entry->uri),
cairo_surface_reference(entry->thumbnail));
}
materialize_icon(self, entry);
}
gtk_widget_queue_resize(GTK_WIDGET(self)); gtk_widget_queue_resize(GTK_WIDGET(self));
} }
@ -928,6 +949,8 @@ fiv_browser_finalize(GObject *gobject)
g_clear_object(&self->model); g_clear_object(&self->model);
} }
g_hash_table_destroy(self->thumbnail_cache);
cairo_surface_destroy(self->glow); cairo_surface_destroy(self->glow);
g_clear_object(&self->pointer); g_clear_object(&self->pointer);
@ -972,6 +995,8 @@ set_item_size(FivBrowser *self, FivThumbnailSize size)
if (size != self->item_size) { if (size != self->item_size) {
self->item_size = size; self->item_size = size;
self->item_height = fiv_thumbnail_sizes[self->item_size].size; self->item_height = fiv_thumbnail_sizes[self->item_size].size;
g_hash_table_remove_all(self->thumbnail_cache);
reload_thumbnails(self); reload_thumbnails(self);
thumbnailers_start(self); thumbnailers_start(self);
@ -1688,6 +1713,9 @@ fiv_browser_init(FivBrowser *self)
g_array_set_clear_func(self->layouted_rows, (GDestroyNotify) row_free); g_array_set_clear_func(self->layouted_rows, (GDestroyNotify) row_free);
abort_button_tracking(self); abort_button_tracking(self);
self->thumbnail_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, (GDestroyNotify) cairo_surface_destroy);
self->thumbnailers_len = g_get_num_processors(); self->thumbnailers_len = g_get_num_processors();
self->thumbnailers = self->thumbnailers =
g_malloc0_n(self->thumbnailers_len, sizeof *self->thumbnailers); g_malloc0_n(self->thumbnailers_len, sizeof *self->thumbnailers);
@ -1703,6 +1731,7 @@ fiv_browser_init(FivBrowser *self)
// --- Public interface -------------------------------------------------------- // --- Public interface --------------------------------------------------------
// TODO(p): Later implement any arguments of this FivIoModel signal.
static void static void
on_model_files_changed(FivIoModel *model, FivBrowser *self) on_model_files_changed(FivIoModel *model, FivBrowser *self)
{ {
@ -1712,8 +1741,6 @@ on_model_files_changed(FivIoModel *model, FivBrowser *self)
if (self->selected) if (self->selected)
selected_uri = g_strdup(self->selected->uri); selected_uri = g_strdup(self->selected->uri);
// TODO(p): Later implement arguments of this FivIoModel signal.
// Or ensure somehow else that thumbnails won't be reloaded unnecessarily.
thumbnailers_abort(self); thumbnailers_abort(self);
g_array_set_size(self->entries, 0); g_array_set_size(self->entries, 0);
g_array_set_size(self->layouted_rows, 0); g_array_set_size(self->layouted_rows, 0);