From e7cd4e5f8c06c381ba35b82813f3b173ea31775d Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Fri, 18 Oct 2013 20:00:04 +0200 Subject: [PATCH] Move page cache to ZathuraRenderer Signed-off-by: Sebastian Ramacher --- callbacks.c | 4 +- render.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++---- render.h | 25 +++++- zathura.c | 147 +++------------------------------- zathura.h | 35 ++------ 5 files changed, 252 insertions(+), 183 deletions(-) diff --git a/callbacks.c b/callbacks.c index 414bcb7..c562d5d 100644 --- a/callbacks.c +++ b/callbacks.c @@ -98,7 +98,7 @@ cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpoi if (zathura_page_get_visibility(page) == false) { zathura_page_set_visibility(page, true); zathura_page_widget_update_view_time(zathura_page_widget); - zathura_page_cache_add(zathura, zathura_page_get_index(page)); + zathura_page_cache_add(zathura->sync.render_thread, zathura_page_get_index(page)); } if (zathura->global.update_page_number == true && updated == false && gdk_rectangle_intersect(¢er, &page_rect, NULL) == TRUE) { @@ -112,7 +112,7 @@ cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpoi /* if the page is not visible and not cached, but still has a surface, we * need to get rid of the surface */ if (zathura_page_widget_have_surface(zathura_page_widget) == true && - zathura_page_cache_is_cached(zathura, zathura_page_get_index(page)) == false) { + zathura_page_cache_is_cached(zathura->sync.render_thread, zathura_page_get_index(page)) == false) { zathura_page_widget_update_surface(zathura_page_widget, NULL); } diff --git a/render.c b/render.c index 050cc4f..1ba7234 100644 --- a/render.c +++ b/render.c @@ -16,13 +16,17 @@ G_DEFINE_TYPE(ZathuraRenderer, zathura_renderer, G_TYPE_OBJECT) G_DEFINE_TYPE(ZathuraRenderRequest, zathura_render_request, G_TYPE_OBJECT) /* private methods for ZathuraRenderer */ -static void zathura_renderer_finalize(GObject* object); +static void renderer_finalize(GObject* object); /* private methods for ZathuraRenderRequest */ -static void zathura_render_request_finalize(GObject* object); +static void render_request_finalize(GObject* object); static void render_job(void* data, void* user_data); static gint render_thread_sort(gconstpointer a, gconstpointer b, gpointer data); static void color2double(const GdkColor* col, double* v); +static ssize_t page_cache_lru_invalidate(ZathuraRenderer* renderer); +static void page_cache_invalidate_all(ZathuraRenderer* renderer); +static bool page_cache_is_full(ZathuraRenderer* renderer, bool* result); + /* private data for ZathuraRenderer */ @@ -31,7 +35,9 @@ typedef struct private_s { mutex mutex; /**< Render lock */ volatile bool about_to_close; /**< Render thread is to be freed */ - /* recolor information */ + /** + * recolor information + */ struct { bool enabled; bool hue; @@ -41,6 +47,18 @@ typedef struct private_s { double dark[3]; GdkColor dark_gdk; } recolor; + + /* + * page cache + */ + struct { + int* cache; + size_t size; + size_t num_cached_pages; + } page_cache; + + /* render requests */ + girara_list_t* requests; } private_t; /* private data for ZathuraRenderRequest */ @@ -68,7 +86,7 @@ zathura_renderer_class_init(ZathuraRendererClass* class) /* overwrite methods */ GObjectClass* object_class = G_OBJECT_CLASS(class); - object_class->finalize = zathura_renderer_finalize; + object_class->finalize = renderer_finalize; } static void @@ -80,21 +98,44 @@ zathura_renderer_init(ZathuraRenderer* renderer) g_thread_pool_set_sort_function(priv->pool, render_thread_sort, NULL); mutex_init(&priv->mutex); + /* recolor */ priv->recolor.enabled = false; priv->recolor.hue = true; - zathura_renderer_set_recolor_colors_str(renderer, "#000000", "#FFFFFF"); -} + /* page cache */ + priv->page_cache.size = 0; + priv->page_cache.cache = NULL; + priv->page_cache.num_cached_pages = 0; -ZathuraRenderer* -zathura_renderer_new() -{ - GObject* obj = g_object_new(ZATHURA_TYPE_RENDERER, NULL); - return ZATHURA_RENDERER(obj); + zathura_renderer_set_recolor_colors_str(renderer, "#000000", "#FFFFFF"); + + priv->requests = girara_list_new(); } static void -zathura_renderer_finalize(GObject* object) +page_cache_init(ZathuraRenderer* renderer, size_t cache_size) +{ + private_t* priv = GET_PRIVATE(renderer); + + priv->page_cache.size = cache_size; + priv->page_cache.cache = g_malloc(cache_size * sizeof(int)); + page_cache_invalidate_all(renderer); +} + +ZathuraRenderer* +zathura_renderer_new(size_t cache_size) +{ + g_return_val_if_fail(cache_size > 0, NULL); + + GObject* obj = g_object_new(ZATHURA_TYPE_RENDERER, NULL); + ZathuraRenderer* ret = ZATHURA_RENDERER(obj); + page_cache_init(ret, cache_size); + + return ret; +} + +static void +renderer_finalize(GObject* object) { ZathuraRenderer* renderer = ZATHURA_RENDERER(object); private_t* priv = GET_PRIVATE(renderer); @@ -104,6 +145,29 @@ zathura_renderer_finalize(GObject* object) g_thread_pool_free(priv->pool, TRUE, TRUE); } mutex_free(&(priv->mutex)); + + free(priv->page_cache.cache); + girara_list_free(priv->requests); +} + +/* (un)register requests at the renderer */ + +static void +renderer_unregister_request(ZathuraRenderer* renderer, + ZathuraRenderRequest* request) +{ + private_t* priv = GET_PRIVATE(renderer); + girara_list_remove(priv->requests, request); +} + +static void +renderer_register_request(ZathuraRenderer* renderer, + ZathuraRenderRequest* request) +{ + private_t* priv = GET_PRIVATE(renderer); + if (girara_list_contains(priv->requests, request) == false) { + girara_list_append(priv->requests, request); + } } /* init, new and free for ZathuraRenderRequest */ @@ -123,7 +187,7 @@ zathura_render_request_class_init(ZathuraRenderRequestClass* class) /* overwrite methods */ GObjectClass* object_class = G_OBJECT_CLASS(class); - object_class->finalize = zathura_render_request_finalize; + object_class->finalize = render_request_finalize; request_signals[REQUEST_COMPLETED] = g_signal_new("completed", ZATHURA_TYPE_RENDER_REQUEST, @@ -163,16 +227,22 @@ zathura_render_request_new(ZathuraRenderer* renderer, zathura_page_t* page) priv->aborted = false; priv->requested = false; + /* register the request with the renderer */ + renderer_register_request(renderer, request); + return request; } static void -zathura_render_request_finalize(GObject* object) +render_request_finalize(GObject* object) { ZathuraRenderRequest* request = ZATHURA_RENDER_REQUEST(object); request_private_t* priv = REQUEST_GET_PRIVATE(request); if (priv->renderer) { + /* unregister the request */ + renderer_unregister_request(priv->renderer, request); + /* release our private reference to the renderer */ g_object_unref(priv->renderer); } } @@ -626,3 +696,129 @@ render_thread_sort(gconstpointer a, gconstpointer b, gpointer UNUSED(data)) /* sort aborted entries earlier so that the are thrown out of the queue */ return priv_a->aborted ? 1 : -1; } + + +/* cache functions */ + +bool +zathura_page_cache_is_cached(ZathuraRenderer* renderer, unsigned int page_index) +{ + g_return_val_if_fail(renderer != NULL, false); + private_t* priv = GET_PRIVATE(renderer); + + if (priv->page_cache.num_cached_pages != 0) { + for (size_t i = 0; i < priv->page_cache.size; ++i) { + if (priv->page_cache.cache[i] >= 0 && + page_index == (unsigned int)priv->page_cache.cache[i]) { + girara_debug("Page %d is a cache hit", page_index + 1); + return true; + } + } + } + + girara_debug("Page %d is a cache miss", page_index + 1); + return false; +} + +static int +find_request_by_page_index(const void* req, const void* data) +{ + const ZathuraRenderRequest* request = req; + const unsigned int page_index = *((const int*)data); + + request_private_t* priv = REQUEST_GET_PRIVATE(request); + if (zathura_page_get_index(priv->page) == page_index) { + return 0; + } + return 1; +} + +static ssize_t +page_cache_lru_invalidate(ZathuraRenderer* renderer) +{ + g_return_val_if_fail(renderer != NULL, -1); + private_t* priv = GET_PRIVATE(renderer); + g_return_val_if_fail(priv->page_cache.size != 0, -1); + + ssize_t lru_index = 0; + gint64 lru_view_time = G_MAXINT64; + + for (size_t i = 0; i < priv->page_cache.size; ++i) { + ZathuraRenderRequest* request = girara_list_find(priv->requests, + find_request_by_page_index, &priv->page_cache.cache[i]); + g_return_val_if_fail(request != NULL, -1); + request_private_t* request_priv = REQUEST_GET_PRIVATE(request); + + if (request_priv->last_view_time < lru_view_time) { + lru_view_time = request_priv->last_view_time; + lru_index = i; + } + } + + ZathuraRenderRequest* request = girara_list_find(priv->requests, + find_request_by_page_index, &priv->page_cache.cache[lru_index]); + request_private_t* request_priv = REQUEST_GET_PRIVATE(request); + + /* emit the signal */ + g_signal_emit(request, request_signals[REQUEST_COMPLETED], 0, NULL); + girara_debug("Invalidated page %d at cache index %zd", + zathura_page_get_index(request_priv->page) + 1, lru_index); + priv->page_cache.cache[lru_index] = -1; + --priv->page_cache.num_cached_pages; + + return lru_index; +} + +static bool +page_cache_is_full(ZathuraRenderer* renderer, bool* result) +{ + g_return_val_if_fail(renderer != NULL && result != NULL, false); + private_t* priv = GET_PRIVATE(renderer); + + *result = priv->page_cache.num_cached_pages == priv->page_cache.size; + + return true; +} + +void +page_cache_invalidate_all(ZathuraRenderer* renderer) +{ + g_return_if_fail(renderer != NULL); + + private_t* priv = GET_PRIVATE(renderer); + for (size_t i = 0; i < priv->page_cache.size; ++i) { + priv->page_cache.cache[i] = -1; + } + priv->page_cache.num_cached_pages = 0; +} + +void +zathura_page_cache_add(ZathuraRenderer* renderer, unsigned int page_index) +{ + g_return_if_fail(renderer != NULL); + if (zathura_page_cache_is_cached(renderer, page_index) == true) { + return; + } + + private_t* priv = GET_PRIVATE(renderer); + bool full = false; + if (page_cache_is_full(renderer, &full) == false) { + return; + } else if (full == true) { + ssize_t idx = page_cache_lru_invalidate(renderer); + + if (idx == -1) { + return; + } + + priv->page_cache.cache[idx] = page_index; + ++priv->page_cache.num_cached_pages; + girara_debug("Page %d is cached at cache index %zd", page_index + 1, idx); + return; + } + + priv->page_cache.cache[priv->page_cache.num_cached_pages++] = page_index; + girara_debug("Page %d is cached at cache index %zu", page_index + 1, + priv->page_cache.num_cached_pages - 1); + return; +} diff --git a/render.h b/render.h index 0963a9e..0b48c85 100644 --- a/render.h +++ b/render.h @@ -44,7 +44,7 @@ GType zathura_renderer_get_type(void); * Create a renderer. * @return a renderer object */ -ZathuraRenderer* zathura_renderer_new(void); +ZathuraRenderer* zathura_renderer_new(size_t cache_size); /** * Return whether recoloring is enabled. @@ -116,6 +116,29 @@ void zathura_renderer_lock(ZathuraRenderer* renderer); */ void zathura_renderer_unlock(ZathuraRenderer* renderer); +/** + * Add a page to the page cache + * + * @param zathura The zathura session + * @param page_index The index of the page to be cached + */ +void zathura_page_cache_add(ZathuraRenderer* renderer, + unsigned int page_index); + +/** + * Checks if the given page is cached + * + * @param zathura The zathura session + * @param page_index The index of the page that may be cached + * + * @return true if page is cached otherwise false + */ +bool zathura_page_cache_is_cached(ZathuraRenderer* renderer, + unsigned int page_index); + + + + typedef struct zathura_render_request_s ZathuraRenderRequest; typedef struct zathura_render_request_class_s ZathuraRenderRequestClass; diff --git a/zathura.c b/zathura.c index bbf2f42..8ba2e80 100644 --- a/zathura.c +++ b/zathura.c @@ -54,9 +54,6 @@ typedef struct position_set_delayed_s { } position_set_delayed_t; static gboolean document_info_open(gpointer data); -static ssize_t zathura_page_cache_lru_invalidate(zathura_t* zathura); -static void zathura_page_cache_invalidate_all(zathura_t* zathura); -static bool zathura_page_cache_is_full(zathura_t* zathura, bool* result); static void zathura_jumplist_reset_current(zathura_t* zathura); static void zathura_jumplist_append_jump(zathura_t* zathura); static void zathura_jumplist_save(zathura_t* zathura); @@ -279,20 +276,6 @@ zathura_init(zathura_t* zathura) zathura->jumplist.size = 0; zathura->jumplist.cur = NULL; - /* page cache */ - - int cache_size = 0; - girara_setting_get(zathura->ui.session, "page-cache-size", &cache_size); - if (cache_size <= 0) { - girara_warning("page-cache-size is not positive, using %d instead", ZATHURA_PAGE_CACHE_DEFAULT_SIZE); - zathura->page_cache.size = ZATHURA_PAGE_CACHE_DEFAULT_SIZE; - } else { - zathura->page_cache.size = cache_size; - } - - zathura->page_cache.cache = g_malloc(zathura->page_cache.size * sizeof(int)); - zathura_page_cache_invalidate_all(zathura); - return true; error_free: @@ -367,8 +350,6 @@ zathura_free(zathura_t* zathura) girara_list_iterator_free(zathura->jumplist.cur); } - g_free(zathura->page_cache.cache); - g_free(zathura); } @@ -710,8 +691,17 @@ document_open(zathura_t* zathura, const char* path, const char* password, zathura->document = document; + /* page cache size */ + int cache_size = 0; + girara_setting_get(zathura->ui.session, "page-cache-size", &cache_size); + if (cache_size <= 0) { + girara_warning("page-cache-size is not positive, using %d instead", + ZATHURA_PAGE_CACHE_DEFAULT_SIZE); + cache_size = ZATHURA_PAGE_CACHE_DEFAULT_SIZE; + } + /* threads */ - zathura->sync.render_thread = zathura_renderer_new(); + zathura->sync.render_thread = zathura_renderer_new(cache_size); if (zathura->sync.render_thread == NULL) { goto error_free; @@ -821,9 +811,6 @@ document_open(zathura_t* zathura, const char* path, const char* password, cb_view_vadjustment_value_changed(NULL, zathura); } - /* Invalidate all current entries in the page cache */ - zathura_page_cache_invalidate_all(zathura); - return true; error_free: @@ -1400,117 +1387,3 @@ zathura_jumplist_save(zathura_t* zathura) cur->y = zathura_adjustment_get_ratio(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view))); } } - -bool -zathura_page_cache_is_cached(zathura_t* zathura, unsigned int page_index) -{ - g_return_val_if_fail(zathura != NULL, false); - - unsigned int i; - - if (zathura->page_cache.num_cached_pages != 0) { - for (i = 0; i < zathura->page_cache.size; ++i) { - if (zathura->page_cache.cache[i] >= 0 && page_index == (unsigned int)zathura->page_cache.cache[i]) { - girara_debug("Page %d is a cache hit", page_index + 1); - return true; - } - } - } - - girara_debug("Page %d is a cache miss", page_index + 1); - return false; -} - -static ssize_t -zathura_page_cache_lru_invalidate(zathura_t* zathura) -{ - g_return_val_if_fail(zathura != NULL, -1); - - ssize_t lru_index = 0; - gint64 view_time = 0; - gint64 lru_view_time = G_MAXINT64; - GtkWidget* page_widget; - - for (unsigned int i = 0; i < zathura->page_cache.size; ++i) { - page_widget = zathura_page_get_widget(zathura, zathura_document_get_page(zathura->document, zathura->page_cache.cache[i])); - g_return_val_if_fail(page_widget != NULL, -1); - g_object_get(G_OBJECT(page_widget), "last-view", &view_time, NULL); - - if (view_time < lru_view_time) { - lru_view_time = view_time; - lru_index = i; - } - } - - zathura_page_t* page = zathura_document_get_page(zathura->document, zathura->page_cache.cache[lru_index]); - g_return_val_if_fail(page != NULL, -1); - - page_widget = zathura_page_get_widget(zathura, page); - g_return_val_if_fail(page_widget != NULL, -1); - - zathura_page_widget_update_surface(ZATHURA_PAGE(page_widget), NULL); - girara_debug("Invalidated page %d at cache index %zd", zathura->page_cache.cache[lru_index] + 1, lru_index); - zathura->page_cache.cache[lru_index] = -1; - --zathura->page_cache.num_cached_pages; - - return lru_index; -} - -static bool -zathura_page_cache_is_full(zathura_t* zathura, bool* result) -{ - g_return_val_if_fail(zathura != NULL && result != NULL, false); - - *result = zathura->page_cache.num_cached_pages == zathura->page_cache.size; - - return true; -} - -void -zathura_page_cache_invalidate_all(zathura_t* zathura) -{ - g_return_if_fail(zathura != NULL); - - unsigned int i; - - for (i = 0; i < zathura->page_cache.size; ++i) { - zathura->page_cache.cache[i] = -1; - } - - zathura->page_cache.num_cached_pages = 0; -} - -void -zathura_page_cache_add(zathura_t* zathura, unsigned int page_index) -{ - g_return_if_fail(zathura != NULL); - - zathura_page_t* page = zathura_document_get_page(zathura->document, page_index); - - g_return_if_fail(page != NULL); - - if (zathura_page_cache_is_cached(zathura, page_index) == true) { - return; - } - - bool full; - - if (zathura_page_cache_is_full(zathura, &full) == false) { - return; - } else if (full == true) { - ssize_t idx = zathura_page_cache_lru_invalidate(zathura); - - if (idx == -1) { - return; - } - - zathura->page_cache.cache[idx] = page_index; - ++zathura->page_cache.num_cached_pages; - girara_debug("Page %d is cached at cache index %zd", page_index + 1, idx); - return; - } - - zathura->page_cache.cache[zathura->page_cache.num_cached_pages++] = page_index; - girara_debug("Page %d is cached at cache index %d", page_index + 1, zathura->page_cache.num_cached_pages - 1); - return; -} diff --git a/zathura.h b/zathura.h index bea5d0a..1ed99a4 100644 --- a/zathura.h +++ b/zathura.h @@ -13,8 +13,6 @@ #include #endif -#define ZATHURA_PAGE_CACHE_DEFAULT_SIZE 15 - enum { NEXT, PREVIOUS, LEFT, RIGHT, UP, DOWN, BOTTOM, TOP, HIDE, HIGHLIGHT, DELETE_LAST_WORD, DELETE_LAST_CHAR, DEFAULT, ERROR, WARNING, NEXT_GROUP, PREVIOUS_GROUP, ZOOM_IN, ZOOM_OUT, ZOOM_ORIGINAL, ZOOM_SPECIFIC, FORWARD, @@ -28,6 +26,12 @@ enum { ZATHURA_PAGE_NUMBER_UNSPECIFIED = INT_MIN }; +/* cache constants */ +enum { + ZATHURA_PAGE_CACHE_DEFAULT_SIZE = 15, + ZATHURA_PAGE_CACHE_MAX_SIZE = 1024 +}; + /* forward declaration for types from database.h */ typedef struct _ZathuraDatabase zathura_database_t; @@ -147,15 +151,6 @@ struct zathura_s gchar* password; /**< Save password */ } file_monitor; - /** - * The page cache - */ - struct { - int* cache; - unsigned int size; - unsigned int num_cached_pages; - } page_cache; - /** * Bisect stage */ @@ -405,22 +400,4 @@ void zathura_jumplist_trim(zathura_t* zathura); */ bool zathura_jumplist_load(zathura_t* zathura, const char* file); -/** - * Add a page to the page cache - * - * @param zathura The zathura session - * @param page_index The index of the page to be cached - */ -void zathura_page_cache_add(zathura_t* zathura, unsigned int page_index); - -/** - * Checks if the given page is cached - * - * @param zathura The zathura session - * @param page_index The index of the page that may be cached - * - * @return true if page is cached otherwise false - */ -bool zathura_page_cache_is_cached(zathura_t* zathura, unsigned int page_index); - #endif // ZATHURA_H